这个haskell代码
map ($ 3) [(4+), (10*), (^2), sqrt]
给出输出
[7.0,30.0,9.0,1.7320508075688772]
我知道$具有最低优先级,因此$右边的表达式一起评估。但我不明白的是($ 3)如何表现为一个函数(因为Map将函数和列表作为参数)。我不明白为什么列表中的每个函数都应用于3。
答案 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
接受并返回浮点值,我们会看到对所有应用程序强制执行此类型。