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