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

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


当前回答

($)允许函数链接在一起,而不需要添加括号来控制求值顺序:

Prelude> head (tail "asdf")
's'

Prelude> head $ tail "asdf"
's'

复合操作符(.)创建一个新函数,但不指定参数:

Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'

Prelude> let second = head . tail
Prelude> second "asdf"
's'

上面的例子可以说是说明性的,但并没有真正显示使用组合的便利性。这里还有一个类比:

Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"

如果我们只使用一次third,我们可以通过使用lambda来避免命名:

Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"

最后,复合让我们避免lambda:

Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"

其他回答

($)允许函数链接在一起,而不需要添加括号来控制求值顺序:

Prelude> head (tail "asdf")
's'

Prelude> head $ tail "asdf"
's'

复合操作符(.)创建一个新函数,但不指定参数:

Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'

Prelude> let second = head . tail
Prelude> second "asdf"
's'

上面的例子可以说是说明性的,但并没有真正显示使用组合的便利性。这里还有一个类比:

Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"

如果我们只使用一次third,我们可以通过使用lambda来避免命名:

Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"

最后,复合让我们避免lambda:

Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"

我想举个简短的例子。而不是$将有助于澄清事情。

double x = x * 2
triple x = x * 3
times6 = double . triple

:i times6
times6 :: Num c => c -> c

请注意,times6是一个由函数组合创建的函数。

$操作符用于避免括号。在它之后出现的任何东西都会优先于在它之前出现的任何东西。

例如,假设你有一行是这样写的:

putStrLn (show (1 + 1))

如果你想去掉这些括号,下面的任何一行也会做同样的事情:

putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1

的主要目的。运算符不是为了避免圆括号,而是为了链函数。它允许您将右边出现的任何输出与左边出现的任何输入联系起来。这通常也会导致括号更少,但工作方式不同。

回到同样的例子:

putStrLn (show (1 + 1))

(1 + 1)没有输入,因此不能与。操作符。 show可以接受Int类型并返回String类型。 putStrLn可以接受String并返回IO()。

你可以这样链式显示strln:

(putStrLn . show) (1 + 1)

如果括号太多,可以用$操作符去掉:

putStrLn . show $ 1 + 1

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

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

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

(|>) x y = y x

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