Haskell中Monad與Applicative的關係?
在Haskell中,Monad 的定義如下:
class Applicative m =&> Monad m where為什麼 一個m在成為Monad的 Instance之前必須是Applicative的Instance
首先,這是一個歷史問題,因為Monad的發現在Applicative之前,所以7.10里要改,已經爭論很多年了。其次,你搞混了依賴關係與實現順序的關係,其實並不是一個序的對應,也就是說你實現Monad不一定要先實現Applicative,實現Applicative不一定要先實現Functor。給你一個例子:
import Control.Applicative
newtype Id a = Id a
instance Monad Id where
return = Id
(&>&>=) (Id x) g = g x
instance Applicative Id where
pure = return
(&<*&>) f x = do
h &<- f
y &<- x
return $ h y
instance Functor Id where
fmap f x = pure f &<*&> x
從上面的代碼里我們可以看到,對於Id類型我先給出了Monad類型類的實現,又通過Monad類型類實現了Applicative,然後又通過Applicative里的pure實現了Functor。這就像是你把一個類型實現為有序類型類Ord的實例了,那麼實現相等類型類實現就可以用Ord里的函數來實現。
也就是說「為什麼 一個m在成為Monad的 Instance之前必須是Applicative的Instance?」這個問題本身就是不對的。重複一次,不對的地方在於m在成為Monad前不一定需要是Applicative與Functor。只是這三種代數結構有Functor =&> Applicative =&> Monad的依賴關係。
當然Haskell與GHC的設計者都不是傻瓜,這些你實現了Monad為什麼還要寫Applicative與Functor的代碼?明顯你寫的時候可以這樣。
import Control.Applicative (Applicative(..))
import Control.Monad (liftM, ap)
-- Monad m
instance Functor m where
fmap = liftM
instance Applicative m where
pure = return
(&<*&>) = ap
對於Functor與Applicative,還可以這樣做,在庫里給出兩個類型類實現的默認聲明:
{-# LANGUAGE FlexibleInstances,UndecidableInstances #-}
import Control.Applicative
import Control.Monad
newtype Id a = Id a deriving (Eq, Show)
instance Monad Id where
return = Id
(&>&>=) (Id x) g = g x
instance Monad a =&> Functor a where
fmap = liftM
instance Monad m =&> Applicative m where
pure = return
(&<*&>) f x = ap
現在好像用一個WrappedMonad來避免這種重複(我沒有仔細看),總之解決的辦法相當多,還可以用元編程。這樣可以避免一堆重複的抽象,化簡了Control.Applicative與Control.Monad庫,比如liftM就是fmap了,sequence就是sequenceA了。這樣我們可以把Monad里的這些從Applicative重複的部分deprecated掉。
並不一定要必須,這麼寫是為了強調Monad是增強版的Applicative,或者是建立在Applicative之上的抽象,也就是說可以基於Applicative得出Monad,也可以直接得出Monad,以前不這樣定義的,那麼問題來了,做出這種修改是否是在裝純?
最近有點有趣的發現(受F#中的`|&>`運算符啟發)。如果我們定義:
let x |&> f = f $ x
let x $&> f = f &<$&> x
let x *&> f = f &<*&> x
let x @&> f = x &>&>= f
則有:
(|&>): a -&> (a -&> b) -&> b
($&>): Functor f =&> f a -&> (a -&> b) -&> f b
(*&>): Applicative f =&> f a -&> f (a -&> b) -&> f b
(@&>): Monad f =&> f a -&> (a -&> f b) -&> f b
這似乎是說,從語法角度來講,Functor、Applicative和Monad只是可以應用某些特殊函數的值?
Functors, Applicatives, And Monads In Pictures (無責任ZT)
https://wiki.haskell.org/Functor-Applicative-Monad_Proposal
推薦閱讀:
※Rust相較於Haskell有何優勢?
※OCaml在寫編譯器上比Haskell好在哪?為何Rust第一個版本採用了OCaml?
※Haskell適合做網站開發嗎?有什麼優缺點?
※什麼是free structure?