Haskell 类型和do符号
这是几个问题合在一起:Haskell 类型和do符号,haskell,monads,Haskell,Monads,这是几个问题合在一起: 在do表示法中,每一行是否必须返回相同的类型?例如,我可以在一个do块中写一行返回IOmonad,另一行返回整数吗?(我的理解是,根据>和>=的脱糖效果,答案是否定的。) 如果不是,那么编译器如何确定行必须全部返回的类型?在我所看到的所有例子中,作者认为我们只是在使用IOmonad,这是一个必然的结论。但是,对于给定的do块,您如何知道每一行必须返回什么 再次假设#1的答案是否定的:如何使用在do块中没有返回正确类型monad的函数?例如,考虑这个WebSoCube代码:
do
表示法中,每一行是否必须返回相同的类型?例如,我可以在一个do
块中写一行返回IO
monad,另一行返回整数吗?(我的理解是,根据>
和>=
的脱糖效果,答案是否定的。)IO
monad,这是一个必然的结论。但是,对于给定的do
块,您如何知道每一行必须返回什么do
块中没有返回正确类型monad的函数?例如,考虑这个WebSoCube代码:
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 ()
application::MVar ServerState->WS.Request->WS.WebSockets WS.Hybi00()
应用程序状态rq=do
WS.AcceptRequestRQ
味精
在do块中,每一行可以返回不同的类型,但它们必须在同一个monad中
- 一行可以返回
IO字符串
,一行可以返回IO整数
,但它们都必须是IO
和哈斯克尔的其他人一样。类型推断。就像在Haskell的其他部分一样,它并不总是有效的,当它不起作用时,您也必须进行注释
有两种方法可以做到这一点
let
,记住必须在GHCi中使用let来声明局部变量,您可以在do
块中执行相同的操作<代码>让someMonad=doSomething
- 注意,在
lift
,可以将另一个单子“提升”到转换器中。变压器通常以T结尾,如StateT。几乎你使用的每个单子都有一个等效的变压器要回答你最后一个问题的最后一部分 假设我想打印
msg
的值。我将如何以一种和do
块的类型不冲突的方式来实现这一点
正如你所知,monad transformers通常就是你所需要的。但是,在这种情况下,WebSockets p
monad不是转换器。但是,它是MonadIO
的一个实例,它是monad堆栈的一个类,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
application::MVar ServerState->WS.Request->WS.WebSockets WS.Hybi00()
应用程序状态rq=do
WS.AcceptRequestRQ
你为什么不试试呢?此外,由于do表示法只是语法糖(正如您所说,它可以翻译成(>>=)
和(>>)
),所以手头的机制与任何其他类型类完全相同,并且不特定于do表示法和Monad
s。抱歉,我在上次编辑时不小心弄乱了代码格式(引入了枚举)。不幸的是,我的更正将包含太少的字符,无法作为编辑。请您再次更正,好吗?是的,我已修复。我看到您试图使用标记编号列表,但它们似乎与代码块冲突。这就是为什么我选择将每个数字放在其自己的段落中。您必须将代码块缩进a f我想还有4个空格(总共8个)可以让它在枚举中工作。