功能应用:为什么在这里使用$?

时间:2009-01-11 20:19:22

标签: function haskell operators pointfree

前一段时间,我问question about $,得到了有用的答案 - 事实上,我以为我明白了如何使用它。

看来我错了:(

此示例显示在教程中:

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

我不能为我的生活看到为什么在那里使用$; ghci也没有帮助我,因为我在那里进行的测试似乎表明与简单省略$的版本等效。有人可以为我澄清一下吗?

3 个答案:

答案 0 :(得分:11)

此处使用$,因为它的优先级低于普通函数应用程序。 编写此代码的另一种方法是:

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)

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

答案 1 :(得分:3)

我想解释为什么恕我直言这不是那里使用的风格:

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

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

f x = something $ x

f = something

f = concat . map f类似,这实际上是无点样式。 哪个更清楚是有争议的,但是无点样式给出了一个不同的观点,这也是有用的,所以有时甚至在不完全需要时也会使用。

编辑:在Alasdair的评论之后,我已经用无点免费取代并修改了一些例子,我应该感谢。

答案 2 :(得分: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