Haskell действительно ленивы. Лень означает, что выражение не оценивается, если это не требуется. Однако лень не означает, что два выражения могут быть оценены в произвольном порядке. Порядок оценки выражений в Haskell имеет значение. Например, рассмотрим вашу und
функцию:
und :: Bool -> Bool -> Bool
und False y = False
und y False = False
Во-первых, я хотел бы отметить, что эта функция является неполной.Полная функция:
und :: Bool -> Bool -> Bool
und False y = False
und y False = False
und y True = True -- you forgot this case
В самом деле, функция und
можно записать более кратко (и более лениво) следующим образом:
-- if the first argument is False then the result is False
-- otherwise the result is the second argument
-- note that the second argument is never inspected
und :: Bool -> Bool -> Bool
und False _ = False
und _ x = x
В любом случае, шаблон сопоставления синтаксиса в Haskell просто синтаксический сахар для выражений case
. Например, исходная функция (неполный) будет обессахаренная до (до альфа-эквивалентности):
und :: Bool -> Bool -> Bool
und x y = case x of False -> False
True -> case y of False -> False
True -> undefined
Из этого мы можем видеть:
- Ваша функция является неполной, поскольку последний случай
undefined
.
- Ваша функция вычисляет второй аргумент, если первый аргумент равен
True
, хотя ему это не нужно. Помните, что выражения case
всегда заставляют оценивать проверяемое выражение.
- Ваша функция сначала проверяет
x
, а затем проверяет y
, если x
- True
. Следовательно, здесь действительно существует явный порядок оценки. Обратите внимание, что если x
оценивается до False
, то y
никогда не оценивается (доказательство того, что und
действительно лениво).
Именно из-за этого порядка оценки, что ваше выражение und (non_term 1) False
расходящимся:
und (non_term 1) False
= case non_term 1 of False -> False
True -> case False of False -> False
True -> undefined
= case non_term 2 of False -> False
True -> case False of False -> False
True -> undefined
= case non_term 3 of False -> False
True -> case False of False -> False
True -> undefined
.
.
.
.
Если вы хотите, вы можете создать функцию, которая имеет другой порядок оценки:
und :: Bool -> Bool -> Bool
und x y = case y of False -> False
True -> x -- note that x is never inspected
Теперь выражение und (non_term 1) False
оценивается в False
. Однако выражение und False (non_term 1)
все еще расходится. Таким образом, ваш главный вопрос:
Есть ли способ реализации und
(на немецком языке, т.е. and
) правильно (а не только частично, как указано выше), так что оба
und (non_term 1) False
и
und False (non_term 1)
return False?
Короткий ответ: нет. Вам всегда нужен определенный порядок оценки; и в зависимости от порядка оценки либо und (non_term 1) False
, либо und False (non_term 1)
расходятся.
Означает ли это, что Haskell ошибочен/неисправен? Нет. Хаскелл поступает правильно и просто не дает никакого ответа. Для человека (который может оценивать оба выражения параллельно) казалось бы, что результат und (non_term 1) False
должен быть False
. Однако компьютеры всегда должны иметь порядок оценки.
Итак, в чем же проблема?По моему скромному мнению, актуальной проблемой является либо/или:
Параллельная оценка. Haskell должен вычислить выражение в обоих направлениях параллельно и выбрать тот, который заканчивается первым:
import Data.Unamb (unamb)
type Endo a = a -> a
bidirectional :: Endo (a -> a -> b)
bidirectional = unamb <*> flip
und :: Bool -> Bool -> Bool
und = bidirectional (&&)
Общая рекурсию. По моему скромному мнению, общая рекурсия слишком сильна для большинства случаев использования: она позволяет писать абсурдные функции, такие как non_term x = non_term (x + 1)
. Такие функции совершенно бесполезны. Если мы не будем рассматривать такие бесполезные функции, как исходные данные, то ваша оригинальная функция und
является отличной функцией для использования (просто используйте последний случай или используйте &&
).
Надеюсь, что это поможет.
Ваша функция ленива, она не закорочена. – Mephy
«ленивый» не означает «делает как можно меньше работы». Это означает, что «значения не вычисляются до тех пор, пока они не понадобятся». –
... и они необходимы, чтобы быть уверенным, что первый случай не соответствует. – rampion