【问题标题】:haskell how to print when function doesn't return IO monad?当函数不返回 IO monad 时,haskell 如何打印?
【发布时间】:2014-05-24 02:31:50
【问题描述】:

我基于它遵循类型和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

我还有一个功能,它不能在屏幕上打印“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等等,但我不会写可编译的程序......

【问题讨论】:

    标签: haskell io monads


    【解决方案1】:

    你不能只是将 IO “堵塞”到一个 monad 中而不让它在某个时候冒泡。您需要做的是使用所谓的 monad 转换器将 Err monad 包裹在 IO 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
    

    【讨论】:

    • Functor m 约束有什么用?我没有看到任何fmaps。
    • 1.当我将 Either 更改为 Err 时出现错误:` 'Err' is applied to too many type arguments In the type m (Err String a)' 2. 当我尝试在 test 函数中使用提升时,我什至得到 Not in scope: 'lift' 如果我导入定义 ErrT 的模块。
    • @JakubKuszneruk 1. 删除String 参数 2. 你导入Control.Monad.Trans了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    • 2016-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    相关资源
    最近更新 更多