這篇文章是對張淞書相關部分的一個轉述,僅作個人備忘使用。
歷史沿革
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]