If you complete your pattern-matchings with a constructor []
and not the catch-all _
, the compiler will have a chance to tell you to look again at the function with a warning the day someone adds a third constructor to lists.
My colleagues and I, working on a large OCaml project (200,000+ lines), force ourselves to avoid partial pattern-matching warnings (even if that means writing | ... -> assert false
from time to time) and to avoid so-called "fragile pattern-matchings" (pattern matchings written in such a way that the addition of a constructor may not be detected) too. We consider that the maintainability benefits.
Прелюдия к Haskell (стандартные функции) содержит много частичных функций, например, head и tail работают только с непустыми списками, но не спрашивают мне почему.
Это частный случай более общего вопроса: «следует ли когда-либо создавать частичные функции». Неполные совпадения с образцом - это только один пример частичных функций.
Как правило, предпочтительны общие функции. Когда вы обнаружите, что смотрите на функцию, которая должна быть частичной, спросите себя, можете ли вы сначала решить проблему в системе типов. Иногда это больше проблем, чем того стоит (например, создание целого типа списков с известной длиной, чтобы избежать проблемы с заголовком []). Так что это компромисс.
Или, может быть, вы просто спрашиваете, есть ли хорошая практика в частичных функциях говорить такие вещи, как
head [] = error "head: empty list"
В этом случае ответ - ДА!
Явное лучше, чем неявное (заимствовано из Дзен Python;))
Это точно так же, как в C переключении перечисления
... Это Лучше написать все случаи (с провалом), чем просто указать по умолчанию
, потому что компилятор сообщит вам, если вы добавляете новые элементы в перечисление, а вы забыли их обработать.
Я думаю, что это во многом зависит от контекста. Вы пытаетесь написать надежный, простой в отладке код или пытаетесь написать что-то простое и лаконичное?
Если бы я работал над долгосрочным проектом с несколькими разработчиками, я бы добавил утверждение, чтобы дать больше полезное сообщение об ошибке. Я также согласен с комментарием Паскаля о том, что отсутствие подстановочного знака было бы идеальным с точки зрения разработки программного обеспечения.
Если бы я работал над проектом меньшего масштаба, над которым я был единственным разработчиком, я бы не стал дважды думать об использовании неполного соответствие. При необходимости вы всегда можете проверить предупреждения компилятора.
Я думаю, это также немного зависит от типов, с которыми вы сопоставляете. На самом деле, к типу списка не будут добавлены дополнительные случаи объединения, поэтому вам не нужно беспокоиться о хрупком сопоставлении.
Неполная обработка шаблонов идиоматична в Haskell, но очень плохой стиль в F # (и OCaml, Standard ML и т. Д.).
Проверка полноты - очень ценный способ отловить ошибки во время компиляции в строгих языках, таких как F #, но ленивые языки, такие как Haskell, часто используют бесконечные ленивые списки, в которых не может возникнуть пустой список, поэтому они (исторически) предпочли краткость статически проверенной правильности.