会发生以下情况:
您将 fromMaybe 映射到一个 IO 值。因此左边部分
fromMaybe <$> (print "A" >> return True)
是一个可以重写的 IO 动作
print "A" >> return (fromMaybe True) :: IO (Maybe Bool -> Bool)
这意味着无论如何都会打印“A”。
请注意,IO monad 都是关于排序操作的,因此 >>= 链中后面的操作永远不会影响是否执行较早的操作。
考虑
fromMaybe <$> (getChar >>= return)
很明显, fromMaybe 应用到的 Char 必须来自实际读取一个字符。并非只有在需要时才读取字符。
如果是这样,下面的代码就没有意义了:
do
a <- getChar
b <- getChar
-- at this point, a and b have been actually read from stdin already
return (a < b)
因为,不知道 (<) 是先计算它的左参数还是右参数。
相反,在任何情况下,a 获取读取的第一个字符的值,而 b 获取第二个字符的值。相应地,代码片段的含义是读取两个字符并检查读取的第一个字符是否低于第二个字符。
事实上,如果一个 IO 操作仅在实际需要其值时才执行,那么许多程序就不会打印任何内容。这是因为代码喜欢
print "A" >> print "B"
故意忽略第一次打印的结果。
出于同样的原因,将始终打印“B”。