【问题标题】:Function application: Why is $ used here?函数应用:这里为什么用$?
【发布时间】:2010-09-30 19:42:22
【问题描述】:

前段时间,我问了一个question about $,得到了有用的答案——其实我以为我知道怎么用了。

看来我错了:(

此示例显示在教程中:

instance Monad [] where
   xs >>= f = concat . map f $ xs

我这辈子都看不懂为什么要在那里使用 $; ghci 也没有帮助我,因为即使我在那里进行的测试似乎也显示出与简单地省略 $ 的版本等价。有人可以帮我澄清一下吗?

【问题讨论】:

    标签: function haskell operators pointfree


    【解决方案1】:

    这里使用$的原因是(.)的类型签名:

    (.) :: (b -> c) -> (a -> c) -> a -> c
    

    我们来了

    map f :: [a] -> [[b]]
    

    concat :: [[b]] -> [b]
    

    所以我们结束了

    concat . map f :: [a] -> [b]
    

    而(.)的类型可以写成

    (.) :: ([[b]] -> [b]) -> ([a] -> [[b]]) -> [a] -> [b]

    如果我们使用concat . map f xs,我们会看到

    map f xs :: [[b]]
    

    因此不能与 (.) 一起使用。 (类型必须是 (.) :: (a -> b) -> a -> b

    【讨论】:

      【解决方案2】:

      我想解释一下为什么恕我直言,这不是那里使用的样式:

      instance Monad [] where
        xs >>= f = concat (map f xs)
      

      concat . map f 是所谓的pointfree-style写作的一个例子;其中 pointfree 的意思是“没有应用点”。请记住,在数学中,在表达式y=f(x) 中,我们说f 应用于点x。在大多数情况下,您实际上可以执行最后一步,替换:

      f x = something $ x
      

      f = something
      

      喜欢f = concat . map f,这实际上是无点风格。 哪个更清楚是有争议的,但无点风格给出了不同的观点,这也很有用,所以有时即使在不完全需要时也会使用。

      编辑:在我应该感谢 Alasdair 的评论之后,我已经用 pointfree 替换了 pointless 并修复了一些示例。

      【讨论】:

      • 我同意,无意义的样式可能很有用,但是我不喜欢在您实际将参数应用于函数时使用它,就像在这种情况下一样。
      • 另外,如果你不小心你可能会做得过火,这是我昨天写的一些代码 ;-) maybe id (((sp . ("string " ++)) .) . shows) mx
      • 'concat . map f $ xs" 不是无点的,以无点样式编写的列表 monad 的绑定将是 '(>>=) = flip concatMap' 或类似的。这是一个无点样式实际上非常清晰的示例。请参阅@987654321 @
      • 我知道这不是point-free,但它类似于pointfree 风格;因为 >>= 已经反转了参数,所以也需要翻转(我忘记了使用 flip 的可能性,这是真的)。​​
      【解决方案3】:

      这里使用$ 是因为它的优先级低于普通函数应用程序。 这段代码的另一种写法是这样的:

      instance Monad [] where
         xs >>= f = (concat . map f) xs
      

      这里的想法是首先构造一个函数 (concat . map f),然后将其应用于其参数 (xs)。如图所示,这也可以通过简单地在第一部分加上括号来完成。

      请注意,在原始定义中省略$ 是不可能的,这将导致类型错误。这是因为函数组合运算符(.)的优先级低于普通函数应用程序,有效地将表达式转换为:

      instance Monad [] where
        xs >>= f = concat . (map f xs)
      

      这没有意义,因为函数组合运算符的第二个参数根本不是函数。尽管以下定义确实有意义:

      instance Monad [] where
        xs >>= f = concat (map f xs)
      

      顺便说一句,这也是我更喜欢的定义,因为在我看来它更清晰。

      【讨论】:

      • 谢谢。我没有意识到 $ 的优先级甚至低于 (.);我一直在精神上将带有 (.) 的行解析为单独的“块”,但情况并非总是如此!我同意按照您的方式编写它会更清晰,或者: concat $ map f xs
      • 我自己更喜欢 "xs >​​>= f = concat $ map f xs"。
      • 我也是,或者在这种情况下:xs >>= f = concatMap f xs
      • "xs >​​>= f = flip (join.fmap)" :)
      • 添加噪声:(>>=) = 翻转 concatMap -- =)
      猜你喜欢
      • 1970-01-01
      • 2021-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-04
      相关资源
      最近更新 更多