了解如何应用Haskell应用函子

时间:2019-02-28 15:15:11

标签: haskell monads applicative maybe

我只是对应用函子有一个简单的问题,以帮助我掌握它们。这只是我在ghci中应用的内容。

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

这对我来说很有意义。基本应用。但是尝试时:

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

给我很多错误。我对原因有所了解。有两个数据构造函数([]Maybe),而<*>函数仅“剥离”其中一个。我想帮助我理解的是haskell到底要逐步尝试直到失败,以及如何解决它并成功地将其计算为:

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

1 个答案:

答案 0 :(得分:9)

您有两个不同的Applicative实例。没错

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

但是[]实例只是尝试将第一个列表中的每个“函数” 应用到第二个列表中的每个值,因此您最终尝试应用

(Just (* 3)) (Just 4)

这是一个错误。

(更准确地说,您的Just值列表具有错误的类型,无法用作<*>的第一个参数。)

相反,您需要在第一个列表上映射<*>

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

(在列表上映射高阶函数通常是首先获取包装函数列表的方式。例如,

> :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是另一种选择。

> 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]

Compose的定义非常简单:

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

神奇之处在于,只要fg都是(适用的)函子,那么Compose f g也是也是(适用的)函子。< / p>

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)

Applicative实例中,您可以看到与我上面使用的(<*>) <$> ...相同的用法。