Вопрос 1: Есть ли какая-то особая причина, по которой также должен быть проверен параметр «В»?Насколько я понимаю, оператор containsB <- do ... не оценивается, если только он не требуется, но я предполагаю, что он может вести себя по-другому, так как это ввод-вывод и, следовательно, он не свободен от побочных эффектов? </p>
Ваш экспериментошибочен, потому что вы выполняете IO
.Одним из важных аспектов IO
является соблюдение порядка IO
операторов.Поэтому, даже если из-за лени нам не нужно определенное значение, часть IO
выполняется.
Это логично в мире IO
: представьте, что мы читаем файл, и у нас естьтри части.Мы читаем первые две части, а затем читаем третью.Но теперь представьте, что из-за лени вторая IO
команда никогда не выполняется.Тогда это будет означать, что третья часть фактически читает вторую часть файла.
Короче говоря из-за IO
, операторы оцениваются .Но только IO
заявления.Таким образом, значение, заключенное в return
, оценивается , а не , если вам это не нужно.Проверка 'b' `elem` s
происходит только тогда, когда она нам нужна.
Однако существуют способы « обмануть » из IO
из этого.Например, trace
(из Debug.Trace
) модуль выполнит « небезопасный ввод-вывод »: он напечатает сообщение об ошибке, если его вычислить.Если мы напишем:
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: Каков наилучший практический подход для получения желаемого поведения (если содержитfalse, containsB не проверяется), не имея дело с вложенными предложениями if-else?
Как уже было сказано, нормальным поведением является то, что containsB
оценивается , а не .Но если вы выполняете действия IO
, эти должны быть выполнены до того, как вы действительно выполните проверку.Это, в сущности, один из аспектов, который обрабатывает оператор (>>=)
для IO
(вы используете этот оператор неявно в блоке do
).