这是几个问题:
在do
表示法中,每行必须返回相同的类型吗?例如,我可以在单个do
块中写入一行返回IO
monad,另一行返回一个整数吗? (我的理解,基于>>
和>>=
的脱糖效果如何起作用,答案是肯定的。)
如果没有,那么编译器如何确定行必须返回的类型?在我所见过的所有例子中,作者认为我们只是与IO
monad一起工作已成定局。但是,对于给定的do
块,您如何知道每行必须返回的内容?
再次假设#1的答案是否定的:你如何使用不在do
块内返回正确种类的monad的函数?例如,考虑这个websockets代码:
application :: MVar ServerState -> WS.Request -> WS.WebSockets WS.Hybi00 ()
application state rq = do
WS.acceptRequest rq
msg <- WS.receiveData :: WS.WebSockets WS.Hybi00 Text
return ()
假设我要打印msg
的值。如何以与do
块的类型不冲突的方式进行此操作?
答案 0 :(得分:8)
IO String
,一行可以返回IO Integer
,但它们都必须为IO
。let
,请记住在GHCi中你必须使用let来声明局部变量,你可以在do
块中做同样的事情。 let someMonad = doSomething
in
lift
的monad,它可以将另一个monad“提升”到变换器中。变形金刚通常以T结尾,例如StateT。你使用的每个monad都有一个等效的变压器。答案 1 :(得分:4)
要回答最后一个问题的最后部分,
假设我要打印
msg
的值。我将如何以与do
块的类型不冲突的方式进行处理?
作为jozefg said in his answer,monad变形金刚通常就是你需要的。但是,在这种情况下,WebSockets p
monad不是变换器。但是,它是MonadIO
的一个实例,它是monad堆栈的一个类,它在底部有IO
“,因此可以让你从它们中运行任意IO
个动作。
MonadIO
类提供类型为
liftIO
liftIO :: MonadIO m => IO a -> m a
在您的情况下,这会变为IO a -> WebSockets Hybi00 a
,因此您可以使用它将print msg
操作从IO ()
转换为WebSockets Hybi00 ()
,然后您可以在do
中使用application :: MVar ServerState -> WS.Request -> WS.WebSockets WS.Hybi00 ()
application state rq = do
WS.acceptRequest rq
msg <- WS.receiveData :: WS.WebSockets WS.Hybi00 Text
liftIO $ print msg
{1}}阻止:
{{1}}