翻转/反转fmap (<$>)?

28
我发现定义如下内容
(%)  = flip fmap

我可以像这样编写代码:

readFile "/etc/passwd" % lines % filter (not . null)

对我来说,这比另一种选择更有意义:

filter (not . null) <$> lines <$> readFile "/etc/passwd"

显然,这只是一个顺序问题。

还有其他人这样做吗?不写代码像这样是否有有效的理由?


8
这个的更常见的名称可能是 <&>,它是使用 lens 中的 (&) = flip ($) 实现的。 - fread2281
5个回答

12

1
base版本4.11.0.0以来 - MikaelF

10

你的操作符(%)正是来自于lens包中的操作符(<&>)

它可以通过以下方式导入:

import Control.Lens.Operators ((<&>))

6

有一个类似的函数适用于 Applicative 类,称为 <**>; 对于 Functor 来说想要或使用它也是完全合理的。不幸的是,<**> 的语义有些不同,因此不能直接扩展到 Functor 上。


4
-- (.) is to (<$>) as flip (.) is to your (%).  

我通常将(&)定义为flip(.),就像你的例子一样,可以将函数组合应用于反向。在我看来,这使得无点代码更易于理解。

6
还有一个 Arrow 组合子 (>>>),对于函数来说它与 (flip (.)) 是相同的。 - Will
谢谢您先生!除了导入样板之外,这将非常有用,因为我可以保持标准代码。 - codebliss
1
请注意,lens 定义了 (&) = flip ($) - fread2281

1

个人而言,我不会使用这样的运算符,因为这样我就必须学习两种程序阅读顺序。


1
我不确定我是否认同这个观点,但它是一个有趣的观点,所以给个赞。出于好奇:您是否因为同样的原因更喜欢使用=<<而不是>>= - Stephan202
1
我之前从未理解过这个陈述。使用标准符号似乎很有意义,因为那样就像 UNIX 管道一样? - codebliss
6
我更喜欢使用<<=而不是>>=,因为在你的单子的Kleisli范畴中,<<=具有清晰的解释形式,该形式可以被反转以得到可理解的余单子定义。 - Edward Kmett
Stephan:话虽如此,你的论点似乎不太恰当。因为给定前者,后者是可以推导出来的,所以更适合使用 >>= 而非 =<<。我知道你关心的是参数顺序。 - Edward Kmett
我不同意。在深度函数组合(尤其是点无形式)中,一个人必须已经颠倒叙述流来解释代码的数据流。同时,>>=确实会导致与数据流匹配的代码流。这些结合起来很容易导致像这样的代码行:action1 >>= action3 . action2 >>= action4,读者必须在一行中多次颠倒阅读顺序才能理解数据流水线。 在这种情况下,翻转函数组合将是有帮助的。 - ulidtko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接