简体   繁体   English

了解如何应用Haskell应用函子

[英]Understanding how haskell applicative functors are applied

I just have a quick question about applicative functors to help me get a grasp on them. 我只是对应用函子有一个简单的问题,以帮助我掌握它们。 This is just stuff I am applying in ghci. 这只是我在ghci中申请的东西。

[(+3),((-) 3),(*3)] <*> [4]
[7,-1,12]

This makes sense to me. 这对我来说很有意义。 Basic application. 基本应用。 But when trying: 但是当尝试:

[(Just (+3)),(Just ((-) 3)),(Just (*3))] <*> [Just 4]

I am given a large amount of errors. 我收到了很多错误。 I have somewhat of an understanding why; 我对原因有所了解。 there are two data constructors ( [] and Maybe ) and the <*> function only "peels back" one of them. 有两个数据构造函数( []Maybe ),而<*>函数仅“剥离”其中一个。 What I'd like to assist my understanding is what exactly haskell is trying to do step by step until it fails, and how you could get around it and have this successfully compute to: 我想帮助我理解的是haskell到底要逐步尝试直到失败,以及如何解决它并成功地将其计算为:

[(Just 7),(Just -1),(Just 12)]

You have two different Applicative instances. 您有两个不同的Applicative实例。 It is true that 的确

Just (* 3) <*> Just 4 == Just 12

but the [] instance just tries to apply each "function" in the first list to each value in the second, so you end up trying to apply []实例只是试图在第一个列表应用的每个“功能”在第二的每个值,所以你最终想申请

(Just (* 3)) (Just 4)

which is an error. 这是一个错误。

(More precisely, your list of Just values just has the wrong type to act as the first argument for <*> .) (更准确地说,您的Just值列表具有错误的类型以用作<*>的第一个参数。)

Instead, you need to need to map <*> over the first list. 相反,您需要在第一个列表上映射<*>

> (<*>) <$> [(Just (+3)),(Just ((-) 3)),(Just (*3))] <*> [Just 4]
[Just 7,Just (-1),Just 12]

(Mapping a higher-order function over a list is how you usually get a list of wrapped functions in the first place. For example, (将高阶函数映射到列表上通常是您通常首先获取已包装函数列表的方式。例如,

> :t [(+3), ((-) 3), (* 3)]
[(+3), ((-) 3), (* 3)] :: Num a => [a -> a]
> :t Just <$> [(+3), ((-) 3), (* 3)]
Just <$> [(+3), ((-) 3), (* 3)] :: Num a => [Maybe (a -> a)]

)


Data.Functor.Compose mentioned in the comments is another option. Data.Functor.Compose提到的Data.Functor.Compose是另一种选择。

> import Data.Functor.Compose
> :t Compose [(Just (+3)),(Just ((-) 3)),(Just (*3))]
Compose [(Just (+3)),(Just ((-) 3)),(Just (*3))]
  :: Num a => Compose [] Maybe (a -> a)
> Compose [(Just (+3)),(Just ((-) 3)),(Just (*3))] <*> Compose [Just 4]
Compose [Just 12,Just (-1),Just 12]
> getCompose <$> Compose [(Just (+3)),(Just ((-) 3)),(Just (*3))] <*> Compose [Just 4]
[Just 12,Just (-1),Just 12]

The definition of Compose is very simple: Compose的定义非常简单:

newtype Compose f g a = Compose { getCompose: f (g a) }

The magic is that as long as f and g are both (applicative) functors, then Compose fg is also a (applicative) functor. 神奇的是,只要fg都是(应用的)仿函数,那么Compose fg 也是 (应用的)仿函数。

instance (Functor f, Functor g) => Functor (Compose f g) where
    fmap f (Compose x) = Compose (fmap (fmap f) x)

instance (Applicative f, Applicative g) => Applicative (Compose f g) where
    pure x = Compose (pure (pure x))
    Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)

In the Applicative instance, you can see the same use of (<*>) <$> ... that I used above. Applicative实例中,您可以看到与我上面使用的(<*>) <$> ...相同的用法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM