Неисчерпывающие шаблоны с синтаксическим сахаром и сопоставлением шаблонов

#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 , но ваше решение, конечно, намного чище!