点(.)和美元符号($)的区别是什么?

根据我的理解,它们都是不需要使用括号的语法糖。


当前回答

简短而甜蜜的版本:

($)调用作为其左实参的函数对作为其右实参的值进行调用。 (.)将作为其左参数的函数组合到作为其右参数的函数上。

其他回答

其他答案都很好。但是关于ghc如何处理$有一个重要的可用性细节,ghc类型检查器允许用更高等级/量化的类型进行初始化。例如,如果你看$ id类型你会发现它将接受一个参数本身是多态函数的函数。类似这样的小事情在等效的打乱操作符中没有相同的灵活性。(这实际上让我怀疑$!是否值得同样的待遇)

我的规则很简单(我也是初学者):

不要使用。如果要传递参数(调用函数),和 如果没有参数,不要使用$(合成一个函数)

这是

show $ head [1, 2]

但从来没有:

show . head [1, 2]

... 或者你可以避免。和$ structures使用管道:

third xs = xs |> tail |> tail |> head

这是在你添加了helper函数之后:

(|>) x y = y x

一个很有用的应用程序,我花了一些时间从Learn You a Haskell非常简短的描述中弄清楚:Since

f $ x = f x

在包含中缀运算符的表达式的右边加圆括号将其转换为前缀函数,可以将($ 3)(4 +)写成类似于(++ ",world")“你好”。

为什么会有人这么做?例如,对于函数列表。两个:

map (++ ", world") ["hello", "goodbye"]
map ($ 3) [(4 +), (3 *)]

map (\x -> x ++ ", world") ["hello", "goodbye"]
map (\f -> f 3) [(4 +), (3 *)]

显然,后一种变体对大多数人来说更具可读性。

学习任何东西(任何函数)的一个好方法是记住所有东西都是函数!一般的咒语是有帮助的,但在特定的情况下,比如运算符,它有助于记住这个小技巧:

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

and

:t ($)
($) :: (a -> b) -> a -> b

只需记住大量使用:t,并将操作符包装在()中!