类型和符号

时间:2013-05-15 03:15:17

标签: haskell monads

这是几个问题:

  1. do表示法中,每行必须返回相同的类型吗?例如,我可以在单个do块中写入一行返回IO monad,另一行返回一个整数吗? (我的理解,基于>>>>=的脱糖效果如何起作用,答案是肯定的。)

  2. 如果没有,那么编译器如何确定行必须返回的类型?在我所见过的所有例子中,作者认为我们只是与IO monad一起工作已成定局。但是,对于给定的do块,您如何知道每行必须返回的内容?

  3. 再次假设#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块的类型不冲突的方式进行此操作?

2 个答案:

答案 0 :(得分:8)

  1. 在do-block中,每一行都可以返回不同的类型,但它们必须位于同一个monad中
    • 一行可以返回IO String,一行可以返回IO Integer,但它们都必须为IO
  2. 和Haskell的其他部分一样。类型推断。就像在Haskell的其余部分中一样,它并不总是有效,当它没有时,你也必须注释。
  3. 有两种方法可以做到这一点
    • let,请记住在GHCi中你必须使用let来声明局部变量,你可以在do块中做同样的事情。 let someMonad = doSomething
      • 注意,没有in
    • Monad变形金刚!这是一个很难解释的主题,但基本上它们是具有特殊功能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}}