我们知道do块只是语法糖。但是,它如何确定它所处的monadic背景?假设我们不在do块中的任何位置使用{{1}}运算符。
答案 0 :(得分:10)
它使用相同的通用类型类机制,用于确定要使用哪个+
,甚至用于文字的数字类型。那是,
do
return True
不会使用它应该使用的特定monad,而只是分配类型Monad m => m Bool
。这个约束表示do-block具有任何 m Bool
的类型m
,它恰好实现了Monad
类型类。此外,每当使用此块时,将从其使用的上下文推断出特定实例。
如果我们使用与特定Monad
绑定的运算符,则会强制该类型变得更具体。例如,如果我们使用modify :: (a -> a) -> State s a -> State s ()
(我在这里为了示例而简化类型),那么这将强制块具有类型State s ...
。通常,Haskell将找出最常用的类型,并使用类型类约束来确保所讨论的类型实现适当的操作。
答案 1 :(得分:7)
也许有些"实用"示例将有所帮助:
foo1 = do
print 5
return 7
-- print belongs to the IO monad. This whole thing is in IO.
foo2 x = do
writeTVar x 7
return 11
-- writeTVar belongs to the STM monad. This whole thing is in STM.
foo3 = do
let x = 5
[1, 2, 3, 4]
-- Last line is a list expression. This whole thing is in the list monad.
foo4 = do
put 7
return 9
-- put is in the State monad. This whole thing is in the state monad.
foo5 = do
x <- magic1
y <- magic2
return (x, y)
-- This is in whatever monad magic1 and magic2 are in.
foo6 = do
return 13
-- Doesn't mention any monad. Works for ALL POSSIBLE MONADS!
foo7 abc def = do
x <- abc
y <- def
return (x, y)
-- Runs in whatever monad abc and def run in.
-- By passing different arguments, you can CHANGE which monad that is!