Является ли оператор && строгим в Хаскеле?

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

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

и C будет гарантировать, что fnB не будет исполняться до fnA возвращает ложь

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

4 ответа

Решение

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

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

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

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

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

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

⊥ && x = ⊥

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

False && ⊥ = False

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

True && ⊥ = ⊥

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

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

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

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

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

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

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

Не совсем. Хаскель чистый (кроме 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 правда. Но реализации Haskell не обязательно должны быть последовательными! Реализация всегда может быть запущена b когда захочет; Ваша единственная гарантия заключается в том, что, согласно таблице, результат выполнения b может повлиять на вашу программу только тогда, когда a правда.)

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

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

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

Другие вопросы по тегам