#haskell #pattern-matching
#haskell #сопоставление с образцом
Вопрос:
Я написал функцию fun1
, которая принимает список и удаляет каждое число, которое больше или равно предыдущим числам.
fun1 (l:ls) =
fun' [l] ls
where
fun' a z =
case z of
[] -> a
_ -> fun' (if (head z) < (last a) then a [head z] else a) (tail z)
Это работает просто отлично:
> fun1 [4,4,5,9,7,4,3,1,2,0]
=> [4,3,1,0]
В последней строке вместо использования head z
и tail z
я хочу использовать z@(x:xs)
синтаксический сахар, который я видел однажды.
Я попробовал это fun2
, но там я получаю неисчерпывающую ошибку шаблонов. Когда я использую case xs of
вместо case z of
этого, функция запускается без выдачи ошибки, но таким образом она либо пропустит последний элемент, либо мне придется снова написать операцию для применения к последнему элементу (чего я, очевидно, не хочу делать).
fun2 (l:ls) =
fun' [l] ls
where
fun' a z@(x:xs) =
case z of -- "case xs of" would work, but will skip the last element
[] -> a
_ -> fun' (if x < (last a) then a [x] else a) xs
Это приводит к ошибке неисчерпывающих шаблонов:
> fun2 [4,4,5,9,7,4,3,1,2,0]
*** Exception: main.hs:(4,5)-(7,61): Non-exhaustive patterns in function fun'
Почему я получаю эту ошибку, когда пытаюсь сопоставить шаблон z
?
Комментарии:
1.
fun1
не определено для непустых списков (и не являетсяfun2
.2. Это правда, но при условии, что один будет вызывать только
fun1
иfun2
с непустыми списками, проблема по-прежнему заключается вfun'
, или я что-то пропустил? Конечно, я мог бы добавитьfun1 [] = []
, но это не решит мою проблему.3. То же самое для
fun'
: вы определили это только в том случае, если второй параметр не является пустым, поэтомуcase z
не имеет смысла: вы сопоставляете шаблон на(x:xs)
4. да: шаблон будет «срабатывать», если все подшаблоны также совпадают.
5.
last
[foo]
Многократное использование и подобное обходится дорого. Вместо этого просто начните выдавать значения напрямую, как вfun1 (l:ls) = fun' l ls where fun' a [] = []; fun' a (x:xs) = if x < a then x : fun' x xs else fun' a xs
.
Ответ №1:
Выражение:
fun' a z@(x:xs)> =
case z of -- "case xs of" would work, but will skip the last element
[] -> a
_ -> fun' (if x < (last a) then a [x] else a) xs
не имеет особого смысла, это означает, что предложение будет «срабатывать» только в том случае, если z
это непустой список, поэтому обращение [] -> …
никогда не сработает, поскольку шаблон (x:xs)
уже ограничивает предложение непустыми списками.
Таким образом, вы можете переписать это в:
fun' a z =
case z of
[] -> a
(x:xs) -> fun' (if x < (last a) then a [x] else a) xs
Для данного образца ввода это возвращает:
Prelude> fun2 [4,4,5,9,7,4,3,1,2,0]
[4,3,1,0]
Комментарии:
1. Спасибо! Я должен был сосредоточиться на использовании этого синтаксического сахара
@(x:xs)
, поэтому я был полностью ослеплен. Сначала я определил второеfun' a [] = a
, но ваше решение, конечно, намного чище!