用作应用性函子(哈斯克尔/ LYAH)(functions as applicative funct

2019-06-26 18:03发布

了解你一个Haskell引入了以下定义的第11章:

instance Applicative ((->) r) where
    pure x = (\_ -> x)
    f <*> g = \x -> f x (g x)

下面,笔者在一些不寻常的挥手从事(“实例​​实施<*>是一个有点神秘,所以它的最好的,如果我们只[在行动表明它没有解释原因]”)。 我希望这里有人可能会帮助我找到答案。

根据应用性类的定义, (<*>) :: f (a -> b) -> fa -> fb

在该实例,用((->)r)fr->(a->b)->(r->a)->(r->b)

所以,第一个问题,就是如何从该类型得到f <*> g = \x -> fx (gx)

但即使我采取的最后一个公式是理所当然的,我有麻烦使其与例子我给GHCI同意。 例如:

Prelude Control.Applicative> (pure (+5)) <*> (*3) $ 4
17

该表达式代替出现一致f <*> g = \x -> f (gx)请注意,在这个版本x之后不会出现f

我意识到这是凌乱的,所以感谢您与我的轴承。

Answer 1:

首先,记得fmap为applicatives定义:

fmap f x = pure f <*> x

这意味着你的例子是一样的(fmap (+ 5) (* 3)) 4 。 该fmap为功能的功能只是组合物,所以你的精确表达式是相同的((+ 5) . (* 3)) 4

现在,让我们想想为什么实例写到事情是这样的。 什么<*>做本质上是在仿函数应用在仿函数的值。 专业到(->) r ,这意味着它适用从由函数返回的函数r通过从函数返回一个值r 返回功能的功能仅仅是一个两个参数的功能。 所以,真正的问题是:你会如何运用的两个参数(函数ra ,返回b )的值a由函数返回r

首先要注意的事情是,你必须返回类型的值(->) r ,这意味着其结果也必须从函数r 作为参考,这里是<*>功能:

f <*> g = \x -> f x (g x)

因为我们要返回一个函数取类型的值r x :: r 我们返回函数必须有一个类型r -> b 。 我们怎样才能类型的值b ? 好了,我们有一个功能f :: r -> a -> b 。 由于r将是该结果函数的参数,我们得到的是免费的。 所以,现在我们已经从一个函数a -> b 。 所以,只要我们有类型的一些价值a ,我们可以得到类型的值b 。 但是,我们如何获得类型的值a ? 好了,我们有另一个功能g :: r -> a 。 因此,我们可以把我们的类型值r参数x ),并用它来获得类型的值a

所以最终的想法很简单:我们使用的参数,首先要获得类型的值a将其插入g 。 该参数具有键入r g具有类型r -> a ,所以我们有一个a 。 然后,我们既插既参数和新值f 。 我们既需要,因为f有型r -> a -> b 。 一旦我们既插既一个ra在,我们有一个b1 。 由于参数是一个lambda,结果有一个类型r -> b ,这是我们想要的。



Answer 2:

通过你原来的问题去,我认为有,你可能会错过一个微妙但很关键的一点。 使用从LYAH最初的例子:

(+) <$> (+3) <*> (*100) $ 5

这是一样的:

pure (+) <*> (+3) <*> (*100) $ 5

这里的关键是pure(+)其具有拳击的效果(+)作为应用型。 如果你看一下如何pure的定义,你可以看到,拆箱,你需要提供一个额外的参数,它可以是任何东西。 应用<*>(+) <$> (+3)我们得到

\x -> (pure (+)) x ((+3) x)

注意在(pure (+)) x ,我们正在申请xpure拆箱(+) 所以我们现在有

\x -> (+) ((+3) x)

添加(*100)获得(+) <$> (+3) <*> (*100)并应用<*>再次,我们得到

\y -> (\x -> (+) ((+3) x)) y ((*100) y) {Since f <*> g = f x (g x)}

5  -> (\x -> (+) ((+3) x)) 5 ((*100) 5)

(\x -> (+) ((+3) x)) 5 (500)

5 -> (+) ((+3) 5) (500)

(+) 8 500

508

所以在最后,在x之后f不是第一个参数我们的二元运算符,它是用来拆箱操作中pure



Answer 3:

“以实例,用((->)r)fr->(a->b)->(r->a)->(r->b)

为什么,那是不对的。 它实际上是(r->(a->b)) -> (r->a) -> (r->b) ,这是相同的(r->a->b) -> (r->a) -> r -> b 。 即,我们映射中缀和返回缀“右手的说法,到只需缀的函数” LHS并返回其结果的函数。 例如,

Prelude Control.Applicative> (:) <*> (\x -> [x]) $ 2
[2,2]


文章来源: functions as applicative functors (Haskell / LYAH)