haskell - 关于惰性的 'and' 子句评估

标签 haskell lazy-evaluation

我不明白为什么以下代码的行为方式如下:

myand :: Bool -> Bool -> Bool
myand True True = True
myand _ _ = False

containsAandB :: String -> IO Bool
containsAandB s = do
  containsA <- do
    putStrLn $ "Check if 'a' is in " ++ s
    return $ 'a' `elem` s
  containsB <- do
    putStrLn $ "Check if 'b' is in " ++ s
    return $ 'b' `elem` s
  return $ containsA `myand` containsB

这是我测试函数时的输出:
*Main> containsAandB "def"
Check if 'a' is in def
Check if 'b' in in def
False

请注意 (&&) 的行为就像 'myand',我只是编写了一个自定义函数来更好地可视化正在发生的事情。
我对 'Check if 'b' is in def 感到惊讶部分自 containsA已经为假,因此无论 containsB 如何都可以评估“myand” .

问题一:containsB 有什么特别的原因吗?也需要评估?我的理解是 containsB <- do ...除非需要,否则不会评估语句,但我的猜测是,由于它是 IO,因此它的行为可能会有所不同,因此没有副作用?

问题2:
在不处理嵌套 containsA 的情况下,获得所需行为的最佳实践方法是什么(如果 containsB 为假,if-else 未选中)条款?

最佳答案

Question 1: Is there a particular reason why containsB has to be evaluated too? My understanding was that the containsB <- do ... statement is not evaluated unless it's required but my guess is that this might behave differently since it's IO and therefore not free of side effects?



你的实验有缺陷,因为你执行了IO . IO 的重要方面之一是IO的顺序吗?声明受到尊重。所以即使由于懒惰,我们也不需要某个值,IO部分被执行。

这在 IO 的世界中是合乎逻辑的。 : 假设我们读取一个文件,我们有三个部分。我们读了前两部分,然后我们读了第三部分。但是现在想象一下,由于懒惰,第二个 IO命令永远不会执行。那么这意味着第三部分实际上读取了文件的第二部分。

简而言之由于 IO ,语句被评估 .但只有 IO陈述。所以包裹在 return 中的值不评估,除非你需要它。支票'b' `elem` s只有在我们需要的时候才会发生。

然而,有一些方法可以“欺骗”IO出此。例如 trace (来自 Debug.Trace )模块将执行“不安全的 IO”:如果它被评估,它将打印错误消息。如果我们写:
Prelude> import Debug.Trace
Prelude Debug.Trace> myand (trace "a" False) (trace "b" False)

我们有:
Prelude Debug.Trace> myand (trace "a" False) (trace "b" False)
a
False

Question2: What's the best practice approach to get the desired behavior (if containsA is false, containsB is not checked) without dealing with nested if-else clauses?



如前所述,正常行为是 containsB不评估。但是如果你执行 IO操作,必须在您实际进行检查之前执行这些操作。这基本上是 (>>=) 的方面之一。 IO 的运算符(您在 do block 中隐含地使用此运算符)句柄。

关于haskell - 关于惰性的 'and' 子句评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50783116/

相关文章:

arrays - 数组的有序笛卡尔积

haskell - 是否可以显示应用 Haskell 类型族函数的结果?

haskell - 从线程中强制退出程序

orm - 什么时候懒惰评估没有用?

node.js 使用惰性解析 csv 文件

rust - 为打印过程的 child 优先惰性评估器设计数据结构

haskell - 从 State 切换到 StateT 后,如何恢复单子(monad)构造列表的惰性求值?

list - Haskell 函数对输入列表进行排序,然后对排序列表进行处理

haskell - 使用无类型类的 monad 重新绑定(bind) do 符号

haskell - 如何重构才不会卡在IO monad里?