应用仿函数:为什么fmap可以使用多个参数的函数?

Fel*_*ter 8 haskell functor applicative

我进入Haskell,发现这本书"让你学习一个Haskell"最有帮助.我是关于applicative functors的部分.

正如书中所示,我对以下内容感到困惑:

(\x y z -> [x, y, z]) <$> (+3) <*> (*2) <*> (/2) $ 5
Run Code Online (Sandbox Code Playgroud)

产生输出:

[8.0,10.0,2.5]
Run Code Online (Sandbox Code Playgroud)

首先,我已经确认了我对ghci关于运算符优先级的怀疑,所以上面等于下面的丑陋声明:

(((\x y z -> [x,y,z]) <$> (+3)) <*> (*2) <*> (/2)) $ 5 
Run Code Online (Sandbox Code Playgroud)

因此,很明显,首先发生的是fmap通过中(<$>)缀运算符调用.

而这正是令人难以置信的核心.fmap(这里显示为中缀(<$>))的定义是:

(<$>) :: (Functor f) => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

但在我正在努力的等式中,(\x y z -> [x, y, z])需要三个论点,而不仅仅是一个.那么类型的第一个参数怎么能(a -> b)满足呢?

我认为它可能与部分应用/ currying有关,但我无法弄明白.我非常感谢你的解释.希望我已经很好地提出了这个问题.

lef*_*out 11

简单回答:Haskell中没有多个参数的函数!

你可以称之为"二元函数"的函数有两个:一个函数需要一个(单个!)元组,而且 - 在Haskell中普遍存在 - curried函数.那些只需要一个参数,但结果又是一个函数.

所以,为了弄清楚例如fmap (+)是什么,让我们写一下

type IntF = Int -> Int

-- (+) :: Int -> IntF
-- fmap :: ( a -> b  ) ->  f a -> f b
--  e.g.:: (Int->IntF) -> f Int->f IntF
Run Code Online (Sandbox Code Playgroud)

在GHCi中自己测试一下:

Prelude> type IntF = Int - > Int
Prelude> let(#)=(+):: Int - > IntF
Prelude>:t fmap(#)
fmap(#):: Functor f => f Int - > f IntF


Chr*_*lor 7

考虑类型的函数

f :: a -> b -> c -> d
Run Code Online (Sandbox Code Playgroud)

哪里d是任何其他类型.由于卷曲,这可以被认为是具有以下类型的功能

f :: a -> (b -> c -> d)
Run Code Online (Sandbox Code Playgroud)

即一个接受a和返回类型函数的函数b -> c -> d.如果你申请fmap,你有

-- the type of fmap, which is also :: (a -> r) -> (f a -> f r)
fmap :: Functor f => (a -> r) -> f a -> f r

-- the type of f
f :: a -> (b -> c -> d)

-- so, setting r = b -> c -> d
fmap f :: f a -> f (b -> c -> d)
Run Code Online (Sandbox Code Playgroud)

现在哪个是正确的类型,可以用作左手参数(<*>).