我是Haskell的新手。我写了自己的monad,它是状态monad,有错误处理:
newtype MyMonad a = MyMonad (State -> Either MyError (State, a))
我在一个小语言的翻译中使用它。现在我想在我的语言中添加一些IO操作(读/写),但我不知道如何在我的内部包含IO monad。我知道我可以将ErrorT,StateT,IO结合起来并实现这个结果但是没有它们还有其他方法吗?
答案 0 :(得分:6)
您可以查看StateT的实施方式:
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
要将状态与IO
合并,您只需IO
代替m
并获取所需类型:s -> IO (a,s)
。
如果您也有错误,这会变成s -> IO (Either e (a, s))
或s -> IO (Either e a, s)
,具体取决于您是否希望失败的计算影响状态。
请注意,如果没有时间机器,您无法使s -> Either e (IO (a, s))
成为monad 。
<强>更新强>
事实证明,即使使用时间机器,你也无法成为一个单子。
为了说明为什么不可能,让我们首先使用()
代替s
来简化我们的monad:data M e a = M { runM :: Either e (IO a) }
现在,想象一下以下程序:
unsafePerformIO :: IO a -> a
unsafePerformIO io = fromLeft $ runM $ do
a <- M $ Right $ io
M $ Left a
显然,这个函数是不可能的,因此M
的monad实例也是不可能的。
机器可以给你的时间是能够像对待IO
一样对待State
。但是,我没有意识到Either e (s -> (a, s))
不是monad。