Является ли оператор && строгим в Хаскеле? - PullRequest
15 голосов
/ 30 сентября 2011

Например, у меня есть операция fnB :: a -> Bool, которая не имеет смысла, пока fnA :: Bool не вернет False. В C я могу объединить эти две операции в один if блок:

if( fnA && fnB(a) ){ doSomething; }

и C гарантируют, что fnB не будет выполняться, пока fnA не вернет false.

Но Haskell ленив, и, как правило, нет гарантии, какая операция будет выполняться первой, пока мы не используем seq, $! или что-то еще, чтобы сделать наш код строгим. Вообще, это то, что нам нужно для счастья. Но, используя оператор &&, я ожидаю, что fnB не будет оцениваться, пока fnA не вернет свой результат. Предоставляет ли Haskell такую ​​гарантию с &&? И будет ли Haskell оценивать fnB, даже если fnA вернет False?

Ответы [ 4 ]

32 голосов
/ 30 сентября 2011

Функция (&&) является строгой во втором аргументе, только если ее первый аргумент равен True. Он всегда строг в своем первом аргументе. Эта строгость / лень гарантируют порядок оценки.

Так что он ведет себя точно так же, как C. Разница в том, что в Haskell (&&) - обычная функция. В Си это было бы невозможно.

Но Haskell ленив, и, как правило, нет никакой гарантии, какая операция будет выполняться первой, пока мы не используем seq, $ !, или что-то еще, чтобы сделать наш код строгим.

Это не правильно. Истина глубже.

Ускоренный курс в строгости:

Мы знаем, что (&&) строг в своем первом параметре, потому что:

⊥ && x = ⊥

Здесь ⊥ - это что-то вроде undefined или бесконечный цикл (⊥ произносится как «дно»). Мы также знаем, что (False &&) не является строгим во втором аргументе:

False && ⊥ = False

Он не может оценить свой второй аргумент, потому что его второй аргумент - ⊥, который не может быть оценен. Однако функция (True &&) является строгой во втором аргументе, потому что:

True && ⊥ = ⊥

Итак, мы говорим, что (&&) всегда строг в своем первом аргументе и строг в своем втором аргументе, только когда первый аргумент равен True.

Порядок оценки:

Для (&&) его строгости достаточно, чтобы гарантировать порядок исполнения. Это не всегда так. Например, (+) :: Int -> Int -> Int всегда строго в обоих аргументах, поэтому любой аргумент может быть оценен первым. Однако вы можете заметить разницу, только перехватывая исключения в монаде IO или используя функцию unsafe.

5 голосов
/ 30 сентября 2011

Как отмечали другие, естественно, (&&) строго в одном из своих аргументов.По стандартному определению он строг в своем первом аргументе.Вы можете использовать flip, чтобы перевернуть семантику.

В качестве дополнительного примечания: обратите внимание, что аргументы (&&) не могут иметь побочных эффектов, поэтому есть только две причины, по которым вам следует позаботиться о том, x && y строгое в y:

  • Производительность: если для вычисления y требуется много времени.
  • Семантика: Если вы ожидаете, что y может быть снизу.
1 голос
/ 31 августа 2016

Haskell ленив, и, как правило, нет никакой гарантии, какая операция будет выполнена первой

Не совсем.Haskell имеет значение pure (кроме unsafePerformIO и реализации IO), и нет способа наблюдать , какая операция будет выполняться первой (за исключением unsafePerformIO иреализация IO).Порядок выполнения просто не имеет значения для результата.

&& имеет таблицу истинности с 9 значениями, включая случаи, когда один или оба аргумента равны undefined, и онточно определяет операцию:

a           b           a && b
True        True        True
True        False       False
True        undefined   undefined
False       True        False
False       False       False
False       undefined   False
undefined   True        undefined
undefined   False       undefined
undefined   undefined   undefined

Пока реализация следует этой таблице, она может выполнять вещи в любом порядке.

(Если вы изучите таблицу, выобратите внимание, что у последовательной реализации нет способа следовать ей, если только сначала не выполняется a, затем b, если a - True. Но реализации на Haskell не обязательно должны быть последовательными!всегда позволял запускать b всякий раз, когда он этого хочет, ваша единственная гарантия состоит в том, что, согласно таблице, результат выполнения b может повлиять на вашу программу только тогда, когда a имеет значение True.)

(Обратите внимание, что «лень» - это единственный способ написать функцию с таблицей истинности, подобной приведенной выше, на языке, подобном C или ML, все пять из liЕсли значение undefined в любом аргументе будет принудительным, в результате будет получено значение undefined, где в Haskell (и в C, поскольку && встроен в язык C) одна из строк может иметь False в качестверезультат вместо этого.)

0 голосов
/ 30 сентября 2011

Я считаю, что это работает так, как вы ожидаете;оцените RHS, если LHS оценивает в True.Однако, предполагая, что RHS не имеет побочных эффектов, как бы вы узнали (или позаботились)?

Редактировать: Я думаю, RHS может быть undefined, и тогда вам будет интересно ...

...