2015-12-15 40 views
7

我剛纔問這個在Haskell的咖啡廳,但我想我還不如問過這裏。以下Monad實例對於Backwards m有效嗎?向後承認Monad實例嗎?

{-# Language RecursiveDo #-} 

import Control.Applicative.Backwards 
import Control.Monad.Fix 

instance MonadFix m => Monad (Backwards m) where 
    m >>= f = Backwards $ 
    do 
     fin <- forwards (f int) 
     int <- forwards m 
     pure fin 

如果是這樣,我還可以加這個嗎?

instance MonadFix m => MonadFix (Backwards m) where 
    mfix f = Backwards $ mfix (forwards . f) 

回答

2

對於此f將需要懶惰,也就是說,效果不能取決於參數。該docs

mfix f執行行動f只有一次,最終的輸出反饋作爲輸入。因此f不應該是嚴格的,因爲當時mfix f的差異會增大。

BUF如果f你的情況m >>= f將以嚴格的,那麼將被傳遞到mfix塊。

讓我們考慮一個實際的例子,其中mreadLine >>= putStrLn。反轉訂單意味着「打印數據,然後讀取它」。除非>>=後面的功能的效果不依賴於輸入,否則這種分歧。

+0

是的,我知道這個限制,這大大限制了實例的效用。我還不清楚這個限制是否影響其有效性*。 – dfeuer

+0

好吧,我想我現在看到這是如何破壞的。我發佈了一個我懷疑證明的答案。 – dfeuer

+2

我聽說GHC 8.0會支持'IO'的時間旅行。 – PyRulez

3

不,這是無效的; monad法則充其量只能以一些近似的方式。作爲Petr Pudlák's answer顯示,Backwards m >>= f不表現非常漂亮,當f是它的參數嚴格。

根據單子法律,

pure() >>= (\() -> m) = m 

但是,隨着這種情況下,如果我沒有記錯,

pure() >>= (\() -> m) = Backwards $ do 
    fin <- forwards (int `seq` m) 
    int <- pure() 
    pure fin 
    = Backwards $ fmap fst $ mfix $ \ ~(_, int) -> do 
    fin <- forwards (int `seq` m) 
    pure (fin,()) 

如果底層的單子是 「嚴」(即,其>>=是嚴格在其左操作數),這將分歧。