Почему в Haskell неисчерпывающие шаблоны не являются ошибками во время компиляции? - PullRequest
29 голосов
/ 27 сентября 2010

Это продолжение Почему я получаю "Неисчерпывающие шаблоны в функции ...", когда я вызываю функцию подстроки Haskell?

Я понимаю, что используя -Wall, GHC может предостеречь от неисчерпывающих закономерностей.Мне интересно, в чем причина того, что по умолчанию не делается ошибка времени компиляции, учитывая, что всегда можно явно определить частичную функцию:

f :: [a] -> [b] -> Int
f [] _  = error "undefined for empty array"
f _ []  = error "undefined for empty array"
f (_:xs) (_:ys) = length xs + length ys

Вопрос не относится к GHC.

Это потому, что ...

  • никто не хотел заставить компилятор Haskell выполнять такой анализ?
  • при неполном поиске по шаблону можно найти некоторые, но не всепадежи?
  • частично определенные функции считаются законными и используются достаточно часто, чтобы не навязывать вид конструкции, показанный выше?Если это так, можете ли вы объяснить мне, почему неисчерпывающие шаблоны полезны / законны?

Ответы [ 2 ]

35 голосов
/ 27 сентября 2010

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

fac 0 = 1
fac n | n > 0 = n * fac (n-1)

То, что это не является исчерпывающим (отрицательные числа не соответствуют ни одному случаю), на самом деле не имеет значения для типичного использования факториальной функции.

Кроме того, для компилятора может быть вообще невозможно определить, является ли совпадение с шаблоном исчерпывающим:

mod2 :: Integer -> Integer
mod2 n | even n = 0
mod2 n | odd n  = 1

Здесь все случаи должны быть рассмотрены, но компилятор, вероятно, не может обнаружить это. Поскольку средства защиты могут быть произвольно сложными, компилятор не всегда может решить, являются ли шаблоны исчерпывающими. Конечно, этот пример лучше написать с помощью otherwise, но я думаю, что он также должен компилироваться в его текущей форме.

14 голосов
/ 27 сентября 2010

Вы можете использовать -Werror, чтобы превратить предупреждения в ошибки. Я не знаю, сможете ли вы превратить только предупреждения о неполных шаблонах в ошибки, извините!

Что касается третьей части вашего вопроса:

Я иногда пишу ряд функций, которые, как правило, тесно работают вместе и имеют свойства, которые вы не можете легко выразить в Haskell. По крайней мере, некоторые из этих функций имеют тенденцию иметь неисчерпывающий характер, обычно это «потребители». Это происходит, например, в функциях, которые являются своего рода инверсиями друг друга.

Пример игрушки:

duplicate :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) = x : x : (duplicate xs)

removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates [] = []
removeDuplicates (x:y:xs) | x == y = x : removeDuplicates xs

Теперь довольно легко увидеть, что removeDuplicates (duplicate as) равен as (всякий раз, когда тип элемента находится в Eq), но в целом duplicate (removeDuplicates bs) падает, потому что существует нечетное количество элементов или 2 последовательные элементы отличаются. Если он не падает, это потому, что bs был создан (или мог быть создан) duplicate в первую очередь !.

Итак, у нас есть следующие законы (не действует в Haskell):

removeDuplicates . duplicate == id
duplicate . removeDuplicates == id (for values in the range of duplicate)

Теперь, если вы хотите предотвратить использование здесь неисчерпывающих шаблонов, вы можете removeDuplicates вернуть Maybe [a] или добавить сообщения об ошибках для пропущенных случаев. Вы могли бы даже сделать что-то вроде

newtype DuplicatedList a = DuplicatedList [a]

duplicate :: [a] -> DuplicatedList a
removeDuplicates :: Eq a => DuplicatedList a -> [a]
-- implementations omitted

Все это необходимо, потому что вы не можете легко выразить 'быть списком четной длины с равными последовательными парами элементов' в системе типов Haskell (если вы не Олег:)

Но если вы не экспортируете removeDuplicates Я думаю, что вполне нормально использовать здесь неисчерпывающие шаблоны. Как только вы его экспортируете, вы потеряете контроль над входными данными и вам придется разобраться с пропущенными делами!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...