作为应用函子的功能(Haskell/LYAH) [英] functions as applicative functors (Haskell / LYAH)

查看:21
本文介绍了作为应用函子的功能(Haskell/LYAH)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Learn You a Haskell 的第 11 章介绍了以下定义:

Chapter 11 of Learn You a Haskell introduces the following definition:

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

在这里,作者进行了一些不寻常的挥手(<*> 的实例实现有点神秘,所以最好我们只是 [在行动中展示它而不解释它]").我希望这里有人能帮我弄清楚.

Here, the author engages in some uncharacteristic hand-waving ("The instance implementation for <*> is a bit cryptic, so it's best if we just [show it in action without explaining it]"). I'm hoping someone here might help me figure it out.

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

在这个例子中,用((->)r)代替f:r->(a->b)->(r->a)->(r->b)

In the instance, substituting ((->)r) for f: r->(a->b)->(r->a)->(r->b)

所以第一个问题是我如何从那种类型得到 f <*>g = x ->f x (g x)?

So the first question, is how do I get from that type to f <*> g = x -> f x (g x)?

但即使我认为最后一个公式是理所当然的,我也很难让它与我提供给 GHCi 的示例一致.例如:

But even if I take that last formula for granted, I have trouble making it agree with examples I give to GHCi. For example:

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

这个表达式看起来与 f <*> 一致.g = x ->f(g x)(注意在这个版本中x不会出现在f之后.

This expression instead appears consistent with f <*> g = x -> f (g x) (note that in this version x doesn't appear after f.

我意识到这很乱,所以感谢您的耐心等待.

I realize this is messy, so thanks for bearing with me.

推荐答案

首先,记住 fmap 是如何为应用程序定义的:

First of all, remember how fmap is defined for applicatives:

fmap f x = pure f <*> x

这意味着您的示例与 (fmap (+ 5) (* 3)) 4 相同.函数的 fmap 函数只是组合,所以你的确切表达式与 ((+ 5) . (* 3)) 4.

This means that your example is the same as (fmap (+ 5) (* 3)) 4. The fmap function for functions is just composition, so your exact expression is the same as ((+ 5) . (* 3)) 4.

现在,让我们想想为什么实例是这样写的.<*> 所做的实质上是将函子中的函数应用于函子中的值.专门针对 (->) r,这意味着它将 r 中的函数返回的函数应用于 r 中的函数返回的值>.返回一个函数的函数只是一个有两个参数的函数.所以真正的问题是:你如何将一个有两个参数(ra,返回 b)的函数应用到一个值 >ar 的函数返回?

Now, let's think about why the instance is written the way it is. What <*> does is essentially apply a function in the functor to a value in the functor. Specializing to (->) r, this means it applies a function returned by a function from r to a value returned by a function from r. A function that returns a function is just a function of two arguments. So the real question is this: how would you apply a function of two arguments (r and a, returning b) to a value a returned by a function from r?

首先要注意的是,你必须返回一个 (->) r 类型的值,这意味着结果也必须是一个来自 r 的函数.作为参考,这里是 <*> 函数:

The first thing to note is that you have to return a value of type (->) r which means the result also has to be a function from r. For reference, here is the <*> function:

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

因为我们想要返回一个函数,它的值类型为 rx :: r.我们返回的函数必须有一个类型 r ->b.我们如何获得 b 类型的值?好吧,我们有一个函数 f :: r ->->b.由于 r 将成为结果函数的参数,我们免费获得它.所以现在我们有一个来自 a -> 的函数.b.所以,只要我们有一个 a 类型的值,我们就可以得到一个 b 类型的值.但是我们如何获得 a 类型的值呢?好吧,我们还有另一个函数 g :: r ->一个.因此,我们可以获取 r 类型的值(参数 x)并使用它来获取 a 类型的值.

Since we want to return a function taking a value of type r, x :: r. The function we return has to have a type r -> b. How can we get a value of type b? Well, we have a function f :: r -> a -> b. Since r is going to be the argument of the result function, we get that for free. So now we have a function from a -> b. So, as long as we have some value of type a, we can get a value of type b. But how do we get a value of type a? Well, we have another function g :: r -> a. So we can take our value of type r (the parameter x) and use it to get a value of type a.

所以最后的想法很简单:我们使用参数首先通过将其插入g 来获取a 类型的值.参数的类型为 rg 的类型为 r ->a,所以我们有一个 a.然后,我们将参数和新值都插入到 f 中.我们需要两者,因为 f 有一个类型 r ->->b.一旦我们同时插入ra,我们就有了一个b1.由于参数在 lambda 中,因此结果的类型为 r ->b,这就是我们想要的.

So the final idea is simple: we use the parameter to first get a value of type a by plugging it into g. The parameter has type r, g has type r -> a, so we have an a. Then, we plug both the parameter and the new value into f. We need both because f has a type r -> a -> b. Once we plug both an r and an a in, we have a b1. Since the parameter is in a lambda, the result has a type r -> b, which is what we want.

这篇关于作为应用函子的功能(Haskell/LYAH)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆