Функция со строгими аргументами

#haskell

#haskell

Вопрос:

Исправленный тест в моем учебнике спрашивает меня, сколько f аргументов являются строгими, f будучи:

 f x 0 z = x == z
f x y z = x
 

Моя первоначальная мысль заключалась в том, что все f аргументы ‘s следует считать строгими, поскольку y вычисляется, чтобы проверить, равно ли оно 0 , и x и z сравниваются, чтобы убедиться, что они оба равны.
И все же ответ заключается в том, что только x и y являются строгими.

Есть какие-либо подсказки относительно того, почему?

Ответ №1:

Прежде всего, вам нужно очень точное определение «строгого», чтобы это имело смысл. Функция f является строгой, если оценка f x whnf приводит x к вычислению whnf. Взаимодействие, которое это имеет с обработкой, немного неудобно, и я собираюсь проигнорировать некоторые потенциальные странности, которые возникают.

Предполагая, что тип здесь f :: Bool -> Int -> Bool -> Bool ваш анализ поведения wrt y является правильным — оценка f x y z whnf всегда будет требовать оценки y , чтобы определить, какое уравнение выбрать. Поскольку это единственный фактор, определяющий, какое уравнение использовать, мы должны разделить анализ на x и z . В первом уравнении оценка результата в whnf приводит к обоим x и z оценивается. Во втором уравнении оценка результата в whnf приводит к оценке x в whnf.

Поскольку x вычисляется в обеих ветвях, эта функция является строгой x . Это немного забавно — это строго так id , как строго. Но это все еще актуально! z однако это совсем другая история. Только одна из ветвей вызывает z оценку, поэтому она не оценивается строго — она оценивается только по требованию. Обычно мы говорим об этом, когда оценка защищена за конструктором или когда применяется функция, а результат не вычисляется, но достаточно условной оценки. f True 1 undefined вычисляется True как . Если f бы было строгое значение in z , это должно было бы вычислить to undefined .

Ответ №2:

Оказывается, что значение f strict во втором аргументе зависит от того, к какому типу он будет разрешен.

Вот доказательство:

 data ModOne = Zero
instance Eq ModOne where
    _ == _ = True -- after all, they're both Zero, right?
instance Num ModOne -- the method implementations literally don't matter

f x 0 z = x == z
f x y z = x
 

Теперь в ghci:

 > f True (undefined :: ModOne) True
True
> f True (undefined :: Int) True
*** Exception: Prelude.undefined
 

И, аналогичным образом, является ли f строгим его третий аргумент, зависит от того, какие значения вы выбираете для первых двух. Доказательство, снова:

 > f True 1 undefined
True
> f True 0 undefined
*** Exception: Prelude.undefined
 

Итак, на самом деле нет простого ответа на этот вопрос! f определенно строга в своем первом аргументе; но два других условно являются одним или другим в зависимости от обстоятельств.

Комментарии:

1. Хороший пример! Предположительно, это указывает на то, что сопоставление шаблонов для экземпляров Num фактически используется Eq под прикрытием? ( Eq является суперклассом Num , поэтому я думаю, что это не было бы безумием.) Это поведение указано где-то в отчете Haskell или это просто то, как GHC решает это сделать?

2. @RobinZigmond Да, он использует (==) under the covers. Это поведение указано здесь .