Haskell: 經典類型類FAM的重新設計

這篇文章是對張淞書相關部分的一個轉述,僅作個人備忘使用。

歷史沿革

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]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章