Проверить утверждения в Haskell?

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

11
задан Nate 6 May 2010 в 20:37
поделиться

4 ответа

Существует ли один общепринятый/быстрый/более эффективный способ, чем остальные?

Стражи - это (довольно сложный) синтаксический сахар для if-then-else, следующего за сопоставлением шаблонов. If-then-else - это синтаксический сахар для case над Bool. Так что эти вещи в основном одинаково эффективны.

Но вот наблюдение: часто бывает легко сделать неэффективно с помощью булева выражения то, что эффективно с помощью совпадения шаблонов. Любимый пример начинающих программистов на Haskell - написать

length xs == 0

что стоит пропорционально длине xs, где

case xs of { [] -> True; _:_ -> False }

стоит постоянное время.

Более точный способ понять, что происходит, заключается в том, что (при отсутствии причудливых расширений вроде шаблонов представления) наихудшая стоимость сопоставления шаблонов пропорциональна количеству конструкторов, появляющихся в левой части - вы просто не можете написать сопоставление шаблонов, которое было бы одновременно дорогим и маленьким. В отличие от этого, размер булева выражения не говорит вам ничего о том, сколько стоит его оценка. В этом смысле, и только в этом смысле, согласование по образцу дешевле, чем if-then-else или guards.

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

11
ответ дан 3 December 2019 в 05:33
поделиться

Ни один из трех вариантов не выполняет одно и то же действие и не может использоваться во всех ситуациях.

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

Пример:

foo (Just x) = x+1 -- Can not do this without a pattern match (except by using
                   -- functions like fromJust that themselves use pattern matches)
foo Nothing = 0 -- You could do this using a pattern guards like
                -- foo x | x==Nothing = 0, but that is less readable and less
                -- concise than using a plain pattern match

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

maybeSqrt (Just x) | x >= 0 = sqrt x
maybeSqrt _ = Nothing

Использование if, это будет выглядеть так (обратите внимание на повторение Nothing):

maybeSqrt (Just x) = if x >= 0 then sqrt x
                     else Nothing
maybeSqrt _ = Nothing

Наконец, if можно использовать без совпадений с образцом. Если вы на самом деле не используете сопоставление с образцом для заданного значения, введение case x of ... просто для того, чтобы вы могли использовать защиту от образца, не имеет смысла, менее читаемо и кратко, чем просто использование if.

4
ответ дан 3 December 2019 в 05:33
поделиться

Я выбираю, основываясь на том, что делает код красивее и легче для чтения. Как отмечает @Don, многие из этих различных форм компилируются в case. Они выглядят по-разному из-за синтаксического сахара, который доступен. Этот сахар не для компилятора, а для людей. Поэтому принимайте решение, основываясь на том, что, по вашему мнению, хотели бы прочитать другие люди, и что кажется читабельным вам.

2
ответ дан 3 December 2019 в 05:33
поделиться

Ну, я не знаю, является ли мышление в терминах «управляющих утверждений» лучшим способом об этом в Haskell. Тем не менее, в конечном итоге все сводится к сопоставлению с образцом; логические условия, такие как if ... then ... else , могут быть определены в терминах сопоставления с образцом в конструкторах, например, для Bool .

Наиболее "примитивной" формой, вероятно, является оператор case - сопоставление с образцом для определений функций - это просто синтаксический сахар над одним определением функции, содержащим одно большое выражение case .

С точки зрения того, что вам следует использовать, выбирайте то, что концептуально является наиболее разумным. Сопоставление с образцом наиболее подходит, когда вам нужно разобрать алгебраический тип данных; Блоки if подходят, когда вам нужен простой результат да / нет для некоторого предиката. Защиты обычно используются, когда вам нужно сочетание деконструкции типа данных и логических предикатов.

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

4
ответ дан 3 December 2019 в 05:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: