Сопоставление с образцом, F # против Эрланга - PullRequest
14 голосов
/ 03 августа 2010

В Erlang вам рекомендуется не соответствовать шаблонам, которые вы на самом деле не обрабатываете. Например:

case (anint rem 10) of
    1 -> {ok, 10}
    9 -> {ok, 25}
end;

- это поощряемый стиль с другими возможными результатами, результатом которых является badmatch. Это согласуется с философией «дай разбить» в Эрланге.

С другой стороны, F # выдаст «неполное сопоставление с образцом» в эквивалентном коде F #, например, здесь .

Вопрос: почему F # не удаляет предупреждение, эффективно увеличивая каждый шаблон, соответствующий утверждению, эквивалентному

|_ -> failwith "badmatch"

и использовать философию "дай разбить"?

Редактировать : Пока есть два интересных ответа: либо избежать ошибок, которые вероятны, когда не обрабатываются все случаи алгебраического типа данных; или из-за платформы .Net. Один из способов выяснить, что это проверка OCaml. Итак, каково поведение по умолчанию в OCaml?

Редактировать : Устранить недопонимание со стороны .Net людей, не имеющих опыта работы в Erlang. Смысл философии Erlang - не создавать плохой код, который всегда вылетает. Let it crash означает , пусть какой-то другой процесс исправит ошибку . Вместо того, чтобы писать функцию, чтобы она могла обрабатывать все возможные случаи, позвольте вызывающей стороне (например) обрабатывать плохие случаи, которые выбрасываются автоматически. Для тех, кто имеет опыт работы с Java, это похоже на различие между наличием языка с отмеченными исключениями, который должен объявлять все, что он может возвращать при каждом возможном исключении, и языком, на котором функции могут вызывать исключения, которые явно не объявлены.

Ответы [ 5 ]

23 голосов
/ 04 августа 2010

F # (и другие языки с сопоставлением с образцом, такие как Haskell и O'Caml) неявно добавляют регистр, который вызывает исключение.

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

С другой стороны, иногда действительно есть случаи, которые следует исключить, и тогда раздражает необходимость ставить всеобъемлющий случай с тем, что часто является ошибочным сообщением об ошибке. Так что это компромисс.

В ответ на ваши изменения это также предупреждение по умолчанию в O'Caml (и в Haskell с -Wall).

13 голосов
/ 03 августа 2010

В большинстве случаев, особенно с алгебраическими типами данных, забывание случая может быть несчастным случаем, а не преднамеренным решением игнорировать случай.Я считаю, что в строго типизированных функциональных языках большинство функций будет полным и поэтому должно обрабатывать каждый случай.Даже для частичных функций часто идеально генерировать конкретное исключение, а не использовать общий сбой сопоставления с образцом (например, List.head выдает ArgumentException, когда дан пустой список).компилятору обычно имеет смысл предупреждать разработчика.Если вам не нравится это поведение, вы можете либо добавить универсальный шаблон, который сам вызывает исключение, либо отключить или проигнорировать предупреждение.

11 голосов
/ 04 августа 2010

почему бы F # не удалить предупреждение

Интересно, что вы спросите это. Бесшумная инъекция источников ошибок во время выполнения абсолютно противоречит философии F # и его родственников. Это считается гротескной мерзостью. Это семейство языков все о статической проверке, поскольку система типов изначально была разработана таким образом, чтобы облегчать именно эти виды статических проверок.

Это резкое различие в философии - именно поэтому F # и Python так редко сравниваются и противопоставляются. «Никогда не встретятся двое», как говорится.

Итак, каково поведение по умолчанию в OCaml?

То же, что и F #: во время компиляции проверяется полнота и избыточность совпадений с образцами, и выдается предупреждение, если совпадение считается подозрительным. Идиоматический стиль также тот же: вы должны писать свой код так, чтобы эти предупреждения не появлялись.

Такое поведение не имеет ничего общего с .NET, и фактически эта функциональность (из OCaml) была правильно реализована только в F # совсем недавно.

Например, если вы используете шаблон в привязке let для извлечения первого элемента списка, потому что вы знаете, что в списке всегда будет хотя бы один элемент:

let x::_ = myList

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

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

let x, _ = myList

Это исчерпывающе, поэтому компилятор доволен и не выдает предупреждение. Этот код не может ошибаться во время выполнения .

Я стал сторонником этого метода еще в 2004 году, когда я произвел рефакторинг около 1kLOC коммерческого кода OCaml, который был основным источником ошибок времени выполнения в приложении (даже если они были явными в форме универсального кода). сопоставлять случаи, когда возникли исключения). Мой рефакторинг удалил все источники ошибок времени выполнения из большей части кода. Надежность всего приложения значительно улучшилась. Более того, мы потратили недели на поиск ошибок с помощью отладки, но мой рефакторинг был завершен в течение 2 дней. Так что эта техника действительно приносит дивиденды в реальном мире.

4 голосов
/ 19 апреля 2012

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

3 голосов
/ 04 августа 2010

OCaml по умолчанию предупреждает вас о неполных совпадениях. Вы можете отключить его, добавив «p» к флагу «-w». Идея этих предупреждений заключается в том, что чаще всего (по крайней мере, по моему опыту) они являются признаком ошибки программиста. Особенно, когда все ваши шаблоны действительно сложны, как Node (Node (Leaf 4) x) (Node y (Node Empty _)), легко пропустить случай. Когда программист уверен, что это не может пойти не так, явное добавление кейса | _ -> assert false является однозначным способом указать на это.

GHC по умолчанию отключает эти предупреждения; но вы можете включить его с помощью -fwarn-incomplete-patterns

...