这篇文章是对张淞书相关部分的一个转述,仅作个人备忘使用。
历史沿革
Functor, Applicative, Monad, 最先提出来的是Functor,用来建模带box的数据。在这种情况下,下一个提出的是Monad,用来建模可能失败的计算(比如Maybe Monad),或者认为是合并箱子(依然比如Maybe Monad)。
在这种情况下,发现Functor和Monad的粒度太粗了,于是引入了Applicative建模一种中间的情况,即函数和数据都带box的情况。张淞的书中提出Pointed,是因为pure的性质太简单,不需要用定律约束,所以在这中间再加一层。
引入Pointed的好处是,可以在每一层抽象只引入一个新的东西。
小结:
Functor:处理箱中数据
Pointed:装箱
Applicative:任意东西可以在箱中
Monad:允许失败
代码
import Prelude hiding (
Functor()
, fmap, (<$>), (<$)
, Applicative()
, pure, (<*>)
, Monad()
, return, join, (>>=), (>>)
)
import Control.Monad (ap)
-- Typeclass Definitions
infixl 4 <$>, <$
class Functor f where
fmap :: (a -> b) -> f a -> f b
(<$>) :: (a -> b) -> f a -> f b
(<$>) = fmap
(<$) :: a -> f b -> f a
(<$) = fmap . const
-- Laws:
-- fmap id == id
-- (f . g) == fmap f . fmap g
-- Minimal Definition: fmap
class Functor f => Pointed f where
point :: a -> f a
-- Laws:
-- Minimal Definition: point
infixl 4 <*>
class Pointed f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
pure = point
-- Laws:
-- [/identity/] @'pure' 'id' '<*>' v = v@
-- [/composition/] @'pure' (.) '<*>' u '<*>' v '<*>' w = u '<*>' (v '<*>' w)@
-- [/homomorphism/] @'pure' f '<*>' 'pure' x = 'pure' (f x)@
-- [/interchange/] @u '<*>' 'pure' y = 'pure' ('$' y) '<*>' u@
-- `'fmap' f x = 'pure' f '<*>' x`
-- If @f@ is also a 'Monad', define @'pure' = 'return'@ and @('<*>') = 'ap'@
-- Minimal Definition: (<*>)
infixl 1 >>, >>=
class Applicative m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
fail :: String -> m a
return = pure
join mma = mma >>= id
(>>=) ma m = join $ fmap m ma
(>>) ma mb = ma >>= \_ -> mb
fail s = error s
-- Laws:
-- 1. join
-- join . return = id :: m a -> m a = join . fmap return
-- join . join = join . fmap join
-- 2. original
-- return a >>= k == k a
-- m >>= return == m
-- m >>= (\x -> k x >>= h) == (m >>= k) >>= h
-- 3. with functor
-- fmap f xs == xs >>= return . f
-- 4. with Applicative: (see Applicative)
-- 5. Haskell Wiki
-- If the Monad definitions are preferred, Functor and Applicative instances can be defined from them with
-- fmap fab ma = do { a <- ma ; return (fab a) } -- ma >>= (return . fab)
-- pure a = do { return a } -- return a
-- mfab <*> ma = do { fab <- mfab ; a <- ma ; return (fab a) } -- mfab >>= (\ fab -> ma >>= (return . fab)) -- mfab `ap` ma
-- Minimal Definition: join or (>>=)
-- An Instance: List Monad
instance Functor [] where
fmap = map
instance Pointed [] where
point x = [x]
instance Applicative [] where
(<*>) = ap
instance Monad [] where
m >>= k = foldr ((++) . k) [] m
test1 = (join . return) [2, 3]