关于懒惰的“和"子句的评估 [英] Evaluation of 'and' clause with regards to laziness

查看:81
本文介绍了关于懒惰的“和"子句的评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白为什么以下代码会表现出这样的行为:

I don't understand why the following code behaves the way it does:

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

这是我测试功能时的输出:

This is the output when I test the function:

*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"进行求值.

Note that (&&) behaves just like 'myand', I just wrote a custom function to better visualize what's happeninig. I'm surprised about the 'Check if 'b' is in def part since containsA is already false so 'myand' can be evaluated regardless of containsB.

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

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?

问题2:
在不处理嵌套的if-else子句的情况下,获得所需行为(如果containsA为false,则不检查containsB)的最佳实践方法是什么?

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?

推荐答案

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

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部分.

Your experiment is flawed because you perform IO. One of the important aspects of IO is that the order of IO statements is respected. So even if due to lazyness, we do not need a certain value, the IO part is executed.

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

This is logical in the world of IO: imagine that we read a file, and we have three parts. We read the first two parts, and then we read the third one. But now imagine that due to laziness, the second IO command is never executed. Then that would mean that third part actually reads the second part of the file.

因此,简而言之由于IO,对语句 进行了评估.但是只有IO语句.因此,除非需要,否则return内包装的值不会被 评估.支票'b' `elem` s仅在我们需要时进行.

So in short due to IO, the statements are evaluated. But only the IO statements. So the value wrapped inside the return is not evaluated, unless you need it. The check 'b' `elem` s only happens when we need it.

但是,有一些方法可以从中"欺骗" IO.例如,trace(来自Debug.Trace)模块将执行"不安全的IO ":给出评估后,它将打印错误消息.如果我们写:

There are however ways to "trick" the IO out of this. For example trace (from the Debug.Trace) module will perform "unsafe IO": it will print the error message given it is evaluated. If we write:

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

问题2: 在不处理嵌套的if-else子句的情况下,获得所需行为(如果containsA为false,不检查containsB)的最佳实践方法是什么?

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块中暗含使用此运算符)处理的方面之一.

Well as said before, normal behavior is that containsB is not evaluated. But if you perform IO actions, those have to be performed before you actually do the checking. This is bascially one of the aspects that the (>>=) operator for IO (you use this operator implcitly in a do block) handles.

这篇关于关于懒惰的“和"子句的评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆