Я написал функцию 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
?
Это правда, но если предположить, что кто-то будет вызывать только fun1
и fun2
с непустыми списками, проблема все равно заключается в fun'
, или я что-то пропустил? Конечно, я мог бы добавить fun1 [] = []
, но это не решит мою проблему.
То же самое для fun'
: вы определили это только в том случае, если второй параметр не пуст, поэтому case z
не имеет смысла: вы сопоставляете шаблон на (x:xs)
Спасибо @WillemVanOnsem! Как я мог этого не видеть! :D
Таким образом, в основном, когда есть такой аргумент, как z@(x:xs)
, он ведет себя более или менее как аргумент (x:xs)
, который дополнительно доступен через z
, а НЕ наоборот (как я думал)? Другими словами: @(x:xs)
работает только для, например. списки, содержащие хотя бы один элемент.
да: шаблон будет «срабатывать», если все подшаблоны также совпадают.
Повторное использование 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
.
Выражение:
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]
Спасибо! Я должен был сосредоточиться на использовании этого синтаксического сахара @(x:xs)
, поэтому я был полностью ослеплен. Сначала я определил второй fun' a [] = a
, но ваше решение, конечно, намного чище!
fun1
не определен для непустых списков (как иfun2
.