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

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

问题描述

学习你的Haskell 引入了下面的定义: - >)r)其中
纯x =(\ - > x)
f< g = \ x - > fx(gx)

在这里,作者参与了一些不寻常的手势( < *>有点神秘,所以最好如果我们只是[在没有解释的情况下展示它在行动中])。



根据适用的类定义,(<>):: f(a - > b) - > f a - > fb



在实例中,将(( - >)r)替换为(a→b)→(r→a)→(r→b)→(c→c) b)



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



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

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

这个表达式看起来与<$ c $一致c> f * g = \ x - > f(gx)(请注意,在此版本中 x 不出现在 f



我意识到这是混乱的,所以感谢你的支持。

首先,请记住为应用程序定义了 fmap

  fmap fx =纯f <*> x 

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



相同,让我们考虑为什么实例是按照它的方式编写的。什么<> does本质上是将functor中的函数应用到functor中的值。到( - >)r ,这意味着它将函数从 r 返回的函数应用于返回的值由 r 中的函数返回一个函数on只是两个参数的函数。所以真正的问题是:如何应用两个参数( r a )的函数,返回 b )从一个函数返回的值 a

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

  f * g = \ x  - > fx(gx)

因为我们想要返回一个函数,它的类型为 r x :: r 。我们返回的函数必须有一个类型 r - > B'/ code>。我们如何获得类型 b 的值?那么,我们有一个函数 f :: r - > a - > B'/ code>。由于 r 将成为结果函数的参数,因此我们可以免费获得它。所以现在我们有一个函数来自 a - > B'/ code>。因此,只要我们具有 a 类型的值,我们就可以得到 b 类型的值。但是,我们如何获得类型 a 的值?那么,我们有另外一个函数 g :: r - >一个。因此,我们可以将 r (参数 x )类型的值用于获取类型 A 。所以最后的想法很简单:我们使用这个参数首先通过插入它来获取类型 a 的值成 g 。参数的类型为 r g 的类型为 r - >一个,所以我们有一个 a 。然后,我们将参数和新值都插入到 f 中。我们需要两者,因为 f 有一个类型 r - > a - > B'/ code>。一旦我们同时插入 r a ,我们就有一个 b1 。由于该参数在lambda表达式中,因此结果的类型为 r - > b ,这就是我们想要的。


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.

According to the applicative class definition, (<*>) :: f (a -> b) -> f a -> f b

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

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

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

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.

解决方案

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

fmap f x = pure f <*> x

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.

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?

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)

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.

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天全站免登陆