我将从map 开始。 map 函数将操作应用于列表中的每个元素。如果我有
add3 :: Int -> Int
add3 x = x + 3
然后我可以使用map 将其应用于Ints 的整个列表:
> map add3 [1, 2, 3, 4]
[4, 5, 6, 7]
所以如果你看一下类型签名
map :: (a -> b) -> [a] -> [b]
您会看到第一个参数是(a -> b),它只是一个接受a 并返回b 的函数。第二个参数是[a],它是a 类型值的列表,返回类型[b],是b 类型值的列表。所以用简单的英语来说,map 函数将一个函数应用于值列表中的每个元素,然后将这些值作为列表返回。
这就是使map 成为高阶函数的原因,它将函数作为参数并用它来处理。另一种查看map 的方法是在类型签名中添加一些括号来实现
map :: (a -> b) -> ([a] -> [b])
所以你也可以把它想象成一个函数,将一个函数从a 转换为b 到一个从[a] 到[b] 的函数。
函数($)具有类型
($) :: (a -> b) -> a -> b
和使用一样
> add3 $ 1 + 1
5
它所做的只是将 right 的内容(在本例中为 1 + 1)传递给 left 上的函数,此处为 add3。为什么这很重要?它有一个方便的 fixity 或运算符优先级,这使得它等同于
> add3 (1 + 1)
所以右边的任何东西在被传递到左边之前基本上都被包裹在括号中。这只是使它对于将多个函数链接在一起很有用:
> add3 $ add3 $ add3 $ add3 $ 1 + 1
比
> add3 (add3 (add3 (add3 (1 + 1))))
因为您不必关闭括号。