2014-05-24 57 views
1

我下面基於它的類型和單子:haskell如何在函數不返回IO monad時打印?

data Err a = Ok a | Bad String 
    deriving (Read, Show, Eq, Ord) 

instance Monad Err where 
    return  = Ok 
    fail  = Bad 
    Ok a >>= f = f a 
    Bad s >>= f = Bad s 

instance Functor Err where 
    fmap = liftM 

我還功能,具有OT打印「ASDF」到屏幕和錯誤結束(這是調試治標不治本):

runStatments :: [Stm] -> State -> Err State 
runStatments [] state = Ok state 
runStatments (s:_) state = case s of 
    PrintStmt exp -> do { 
    e <- evalExpression exp state; 
    k <- Ok $putStrLn "asfd"; 
    Bad "damn!" 
    } 
    ... 

問題是代碼不能在屏幕上打印「asdf」...

什麼是溫和的解決方案這樣的問題?我試過liftIO等等,但我沒有編寫可編譯的程序...

回答

3

你不能只是將IO「塞進」monad,而不會在某些時候冒泡。你所要做的就是將Err monad包圍在IO monad周圍,並稱之爲monad變換器。

import Control.Monad 
import Control.Monad.Trans 

-- If you don't like `Either`, you can change it to 
-- Err 
data ErrT m a = ErrT {runErrT :: m (Either String a)} 

instance (Monad m, Functor m) => Monad (ErrT m) where 
    return = ErrT . return . Right 
    (ErrT m) >>= f = ErrT $ do 
     val <- m 
     case val of 
      Left err -> return $ Left err 
      Right a -> runErrT $ f a 

instance MonadTrans ErrT where 
    lift = ErrT . liftM Right 

東西然後,你可以做這樣的事情

test :: ErrT IO() 
test = lift $ putStrLn "Hello World" 

main = runErrT test 
+0

什麼的'函子M'約束?我沒有看到任何'fmap's。 – dfeuer

+0

1.當我更改爲Err時,出現錯誤:''Err'應用於太多類型參數在'm(Err String a)'類型中2.當我嘗試在'test'中使用lift時函數我得到'不在範圍內:'提升''即使我導入模塊的地方ErrT被定義。 –

+0

@JakubKuszneruk 1.刪除'String'參數2.是否導入了'Control.Monad.Trans'? – jozefg