需要帮助理解haskell中的函数应用程序运算符

时间:2017-01-02 06:18:04

标签: haskell

这个haskell代码

map ($ 3) [(4+), (10*), (^2), sqrt]  

给出输出

[7.0,30.0,9.0,1.7320508075688772]  

我知道$具有最低优先级,因此$右边的表达式一起评估。但我不明白的是($ 3)如何表现为一个函数(因为Map将函数和列表作为参数)。我不明白为什么列表中的每个函数都应用于3。

2 个答案:

答案 0 :(得分:5)

请记住($)实际上是一个函数:

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

($ 3)\f -> (f $ 3)的简写。它的类型?良好:

3     ::                  Double -- for sake of simplicity
($)   :: (a      -> b) -> a      -> b
($ 3) :: (Double -> b)           -> b

所以($ 3)是一个函数,它将函数从Double转换为某个函数并将该函数应用于3。现在,如果我们使用map,我们最终会:

map ($ 3) [(4+), (10*), (^2), sqrt]  
 = [($ 3) (4+), ($ 3) (10*), ($ 3)(^2), ($ 3) sqrt]  
 = [(4+) $ 3, (10*) $ 3, (^2) $ 3, sqrt $ 3]  
 = [4 + 3, 10 * 3, 3 ^ 2, sqrt 3]
 = [7, 30, 9, sqrt 3]

答案 1 :(得分:3)

我们首先检查($)的类型签名:

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

定义:

($) f x = f x

或者:

f $ x = f x

以上,我们有部分,我们创建了($)的部分应用版本,第二个参数(类型a)设置为{{1 }}。现在,我们知道3的类型为3,因此部分应用的类型签名必须为Num a => a

接下来,让我们看一下列表中的每个函数,每个函数都是($ 3)的参数。正如预期的那样,它们是函数,事实证明它们的类型Num a => (a -> b) -> b实际上比所需的约束更多(所以我们很好)。为了清楚起见,我们可以看看一个应用程序会带来什么:

Num a -> a -> a

我们可以在没有以下部分的情况下重写:

($3) (4+)

从上面的函数定义中可以清楚地看出应用程序是如何进行的。

最后一个令人困惑的部分可能是列表($) (4+) 3 的类型评估为($3) (4+),而不是{1}}。如果我们记得列表是同类的并且注意到列表中的一个函数7接受并返回浮点值,我们会看到对所有应用程序强制执行此类型。