#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. Это поведение указано здесь .