2014-09-12 80 views
13

問題主要在標題中。這似乎是mfix可以爲任何一元計算定義,即使它可能發散:是否有Monad的實例,但不是MonadFix的實例?

mfix :: (a -> m a) -> m a 
mfix f = fix (join . liftM f) 

什麼是錯的這種結構?此外,爲什麼MonadMonadFix類型類是分開的(即哪些類型的實例是Monad而不是MonadFix)?

+3

繼續monad沒有所需的定點操作符。 – augustss 2014-09-12 22:45:44

+1

另請參閱[爲什麼MonadFix的實例不能用於連續monad?](http://stackoverflow.com/q/25827227/1333025)。 – 2014-09-14 15:48:45

回答

16

left shrinking (or tightening) law says

mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y) 

具體而言,這意味着

mfix (\x -> a' >> f x) = a' >> mfix f 

這意味着內部mfix的一元行動必須精確評估一次。這是您的版本無法滿足的MonadFix的主要屬性之一。

下面這個例子,創建一個循環可變列表(讓我們忽視的事實是,你可以做,沒有mfix由於可變性):

import Control.Monad 
import Control.Monad.Fix 
import Data.IORef 

data MList a = Nil | Cons a (IORef (MList a)) 

mrepeat :: a -> IO (MList a) 
mrepeat x = mfix (liftM (Cons x) . newIORef) 

main = do 
    (Cons x _) <- mrepeat 1 
    print x 

有了您的mfix變種調用mrepeat無法完成,因爲你無限期地呼叫newIORef的內部部分。

6

您的mfix的定義不能保證等同於標準的定義。事實上,至少在名單單子很嚴格:

> take 1 $ mfix (\x -> [1,x]) 
[1] 
> let mfix2 :: Monad m => (a -> m a) -> m a; mfix2 f = fix (join . liftM f) 
> take 1 $ mfix2 (\x -> [1,x]) 
Interrupted.