Haskell 学习笔记四:Applicative

Hacks Apr 16, 2020

Applicative 这玩意说起来复杂,其实和 Functor 也差不多,都是一种 typeclass。

祖师爷 Dijkstra 曾经说过:

A formula is worth a thousand pictures

很多东西嘛,用文字表达真的麻烦,看看声明就懂了:

class (Functor f) => Applicative f where  
    pure :: a -> f a  
    (<*>) :: f (a -> b) -> f a -> f b  

第一行:Applicative 是一种 Functor。一个 typeclass 要成为一个 Applicative,它必须首先是一个 Functor。
第二行:Applicative 必须实现 pure 函数。它的参数是任何东西(值或者函数都可以),输出是一个装着这个参数的默认的盒子。
第三行:Applicative 必须实现 <*> 函数。第一个输入是【装着函数的盒子】(wrapped function),第二个输入是一个 wrapped value。

听起来可能会很复杂,但是最重要的就是:函数本身也是可以被装进盒子的(上次讲过了)。<*> 接受的第一个参数就是一个 a -> b函数的盒子。

举个例子:

Prelude> Just (+1) <*> Just (1)
Just 2

Maybe 是一个 Applicative。通过 <*>,我们可以把一个函数的包裹和另一个值的包裹串起来。

我们再来看看 Maybe 的实现代码:

instance Applicative Maybe where
    pure = Just

    Just f  <*> m       = fmap f m
    Nothing <*> _m      = Nothing

pure 作为最基本最简单的【装进盒子】操作,当然是直接等同于 Just 了。<*> 也很简单,把 f 拿出来,用上次讲过的 fmap 串一串。出来的也是一个 wrapped value(不要忘了 Applicative 必须是 Functor)。

非常简洁优雅。有了 Applicative,你就可以这样:

Prelude>  (+) <$> (Just 1) <*> (Just 2)
Just 3

相对比没有用 Applicative 的版本:

Prelude> (+) 1 2
3

完 全 一 致,把一个普通的函数用在 Applicative 上实在是非常简单。

aLPHAtOAD

太年轻,太简单,有时候幼稚。