Согласование образцов, F # vs Erlang
В Erlang вам предлагается не сопоставлять шаблоны, которые вы на самом деле не обрабатываете. Например:
case (anint rem 10) of
1 -> {ok, 10}
9 -> {ok, 25}
end;
- это стиль, который рекомендуется, с другими возможными результатами, приводящими к результату badmatch
. Это согласуется с философией "пусть это вредит" в Эрланге.
С другой стороны, F # выдает "неполное соответствие шаблонов" в эквивалентном коде F #, например здесь.
Вопрос: почему бы F # не удалить предупреждение, эффективно, увеличив каждый шаблон, сопоставляемый с выражением, эквивалентным
|_ -> failwith "badmatch"
и использовать философию "пусть это крушит"?
Изменить: два интересных ответа: либо избежать ошибок, которые могут возникнуть, если не обрабатывать все случаи алгебраического типа данных; или из-за платформы .Net. Один из способов узнать, что проверить OCaml. Итак, каково поведение по умолчанию в OCaml?
Изменить. Чтобы удалить недоразумения .Net, которые не имеют опыта работы в Erlang. Цель философии Эрланга - не создавать плохой код, который всегда сбой. Пусть это сбой означает пусть какой-то другой процесс исправит ошибку. Вместо того, чтобы записывать функцию так, чтобы она могла обрабатывать все возможные случаи, позвольте вызывающему (например) обращаться с плохими случаями, которые выбрасываются автоматически. Для тех, у кого есть Java-фон, это похоже на разницу между наличием языка с проверенными исключениями, который должен объявить все, что он, возможно, будет возвращать с любым возможным исключением, и иметь язык, в котором функции могут создавать исключения, которые явно не объявлены.
Ответы
Ответ 1
F # (и другие языки с сопоставлением с образцом, такие как Haskell и O'Caml) неявно добавляют случай, который генерирует исключение.
По моему мнению, самая ценная причина для полного соответствия шаблонов и внимания к предупреждению заключается в том, что он упрощает рефакторинг, расширяя свой тип данных, потому что компилятор затем предупредит вас о коде, который вы еще не обновили с новым случаем.
С другой стороны, иногда действительно есть случаи, которые следует оставить без внимания, а затем раздражать, чтобы вставить все в ловушку с тем, что часто является плохим сообщением об ошибке. Так что это компромисс.
В ответ на ваше редактирование это также предупреждение по умолчанию в O'Caml (и в Haskell с -Wall).
Ответ 2
В большинстве случаев, особенно с алгебраическими типами данных, забывание о случае, скорее всего, является случайностью, а не преднамеренным решением игнорировать случай. В строго типизированных функциональных языках я считаю, что большинство функций будут полными и поэтому должны обрабатывать каждый случай. Даже для частичных функций он часто идеален, чтобы генерировать конкретное исключение, а не использовать общий сбой шаблона (например, List.head
выдает ArgumentException
при заданном пустом списке).
Таким образом, я думаю, что обычно компилятор имеет смысл предупреждать разработчика. Если вам не нравится это поведение, вы можете либо добавить шаблон catch-all, который сам генерирует исключение, либо выключить или проигнорировать предупреждение.
Ответ 3
почему бы F # не удалить предупреждение
Интересно, что вы спросите об этом. Молчаливые инъекции источников ошибок во время выполнения абсолютно противоречат философии F # и ее родственникам. Это считается гротескной мерзостью. Это семейство языков посвящено статической проверке, в той степени, в которой система типов была в основном разработана для облегчения именно таких статических проверок.
Это резкое различие в философии - именно то, почему F # и Python настолько редко сравниваются и контрастируют. "Никогда не будут встречаться два", как говорится.
Итак, каково поведение по умолчанию в OCaml?
То же, что и F #: исчерпываемость и избыточность совпадений шаблонов проверяется во время компиляции и выдается предупреждение, если совпадение считается подозрительным. Идиоматический стиль тоже одинаков: вы должны написать свой код, чтобы эти предупреждения не отображались.
Это поведение не имеет ничего общего с .NET, и на самом деле эта функциональность (из OCaml) была недавно реализована правильно в F # совсем недавно.
Например, если вы используете шаблон в привязке let
для извлечения первого элемента списка, потому что знаете, что в списке всегда будет хотя бы один элемент:
let x::_ = myList
В этом семействе языков это почти всегда указывает на недостаток дизайна. Правильное решение - представлять ваш непустой список, используя тип, который делает невозможным представление пустого списка. Статическая проверка типов доказывает, что ваш список не может быть пустым и, следовательно, гарантирует, что этот источник ошибок во время выполнения полностью исключен из вашего кода.
Например, вы можете представить непустой список как кортеж, содержащий головку и хвост. Тогда ваш шаблон будет выглядеть следующим образом:
let x, _ = myList
Это является исчерпывающим, поэтому компилятор счастлив и не выдает предупреждение. Этот код не может ошибиться во время выполнения.
Я стал сторонником этой техники еще в 2004 году, когда я переработал около 1 кОК коммерческого кода OCaml, который был основным источником ошибок во время выполнения в приложении (хотя они были явными в виде catch-all которые делали исключения). Мой рефакторинг удалил все источники ошибок во время выполнения из большинства кода. Надежность всего приложения значительно улучшилась. Более того, мы потратили много времени на поиски ошибок при отладке, но мой рефакторинг был завершен в течение 2 дней. Таким образом, этот метод действительно выплачивает дивиденды в реальном мире.
Ответ 4
OCaml по умолчанию предупреждает вас о неполных совпадениях. Вы можете отключить его, добавив "p" в флаг "-w". Идея с этими предупреждениями заключается в том, что чаще всего (по крайней мере, по моему опыту) они являются признаком ошибки программиста. Особенно, когда все ваши шаблоны действительно сложны, например Node (Node (Leaf 4) x) (Node y (Node Empty _))
, легко пропустить случай. Когда программист уверен, что он не может пойти не так, явное добавление случая | _ -> assert false
- это однозначный способ указать это.
GHC по умолчанию отключает эти предупреждения; но вы можете включить его с помощью -fwarn-incomplete-patterns
Ответ 5
Erlang не может иметь исчерпывающее сопоставление шаблонов из-за динамических типов, если у вас нет уловки в каждом, что просто глупо. Окамл, с другой стороны, может. Ocaml также пытается вытолкнуть все проблемы, которые могут быть уловлены во время компиляции.