2012-02-01 28 views

回答

26

那麼,fmap只是(a -> b) -> f a -> f b,即我們想要用一個純函數來轉換monadic動作的結果。這很簡單,用做記號寫:

fmap f m = do 
    a <- m 
    return (f a) 

,或者寫着 「原始」:

fmap f m = m >>= \a -> return (f a) 

這可作爲Control.Monad.liftM

pure :: a -> f a當然是return(<*>) :: f (a -> b) -> f a -> f b有點棘手。我們有一個動作返回一個函數,一個動作返回它的參數,我們想要一個返回結果的動作。在再做記號:

mf <*> mx = do 
    f <- mf 
    x <- mx 
    return (f x) 

或者脫:

mf <*> mx = 
    mf >>= \f -> 
    mx >>= \x -> 
    return (f x) 

田田!這可作爲Control.Monad.ap,所以我們可以給的FunctorApplicative一個完整的實例任何單子M如下:

instance Functor M where 
    fmap = liftM 

instance Applicative M where 
    pure = return 
    (<*>) = ap 

理想情況下,我們就可以直接在Monad指定這些實現,以減輕負擔爲每個monad定義單獨的實例,例如this proposal。如果發生這種情況,將Applicative設爲Monad的超類並不存在真正的障礙,因爲它可以確保它不會破壞任何現有的代碼。另一方面,這意味着爲給定的Monad定義FunctorApplicative實例所涉及的樣板很少,所以很容易成爲「好公民」(並且應該爲任何monad定義這樣的實例)。

+5

這個答案缺少一個重要的部分:證明如果一個給定的'Monad'實例'm'確實滿足Monad定律,那麼你提供給'fmap','pure'和[(<*>)'的單子定義'服從法師和適用法律。 Haskell強制執行的是類型檢查。 – 2012-02-03 02:04:22

10

fmap = liftM(<*>) = ap。以下是指向liftMap的源代碼的鏈接。我認爲你知道如何去掉符號。

相關問題