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

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


当前回答

它们有不同的类型和不同的定义:

infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)

infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x

($)旨在取代普通的函数应用程序,但在不同的优先级,以帮助避免括号。(.)用于将两个函数组合在一起,生成一个新函数。

在某些情况下,它们是可以互换的,但在一般情况下并非如此。典型的例子是:

f $ g $ h $ x

==>

f . g . h $ x

换句话说,在$s链中,除了最后一个,其他的都可以被。

其他回答

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

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

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

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

还要注意,($)是专门用于函数类型的标识函数。恒等函数是这样的:

id :: a -> a
id x = x

While($)是这样的:

($) :: (a -> b) -> (a -> b)
($) = id

注意,我有意在类型签名中添加了额外的括号。

($)的使用通常可以通过添加圆括号来消除(除非在节中使用运算符)。例如:f $ g x变成f (g x)。

(.)的使用通常稍难替换;它们通常需要一个lambda或显式函数形参的引入。例如:

f = g . h

就变成了

f x = (g . h) x

就变成了

f x = g (h x)

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

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"

一个很有用的应用程序,我花了一些时间从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 *)]

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

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

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

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

(|>) x y = y x