Понимание списка Haskell Неисчерпывающий шаблон при вызове более одного параметра
Для начала я создал Type StudentMark, который является кортежем, во-первых, с использованием String, а затем с Int.
type StudentMark = (String, Int)
Это моя функция capMarks:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
А вот моя функция capMark:
capMark :: StudentMark -> StudentMark
capMark (st, mk)
| mk > 39 = (st, 40)
| mk < 40 = (st, mk)
Предполагается вернуть:
[("Jo", 37), ("Sam", 40)]
от:
capMarks [("Jo", 37), ("Sam", 76)]
Но верный и ожидаемый ответ вернется только тогда, когда я введу только 1 параметр в функцию, например:
capMarks [("Jake", 50)]
Или же
capMarks [("Jake"), 30]
Но использование двух (или более), как предполагается, просто скажет мне, что в функции capMarks есть неисчерпывающий шаблон.
2 ответа
Давайте проанализируем ваши capMarks
функция:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
Прежде всего capMarks [cMarks] = ...
это сопоставление с образцом. Это соответствует списку, который содержит один элемент. Я предполагаю, что вы хотите сделать что-то со всем списком, поэтому измените это на capMarks cMarks = ...
следующий ... [(st, mk) | (st, mk) <- [capMark cMarks]]
будет применять capMark
работать с единственным элементом в вашей исходной схеме сопоставления с образцом, а затем поместить результат как единственный элемент списка. Похоже, что вы хотите подать заявку capMark
к каждому элементу списка. Поэтому, если мы последуем предыдущему предложению, вам нужно сделать что-то вроде ... [capMark mark | mark <- cMarks]
, Это в точности как указано ранее: применить capMark
к каждому элементу cMarks
список.
Окончательный вариант:
capMarks :: [StudentMark] -> [StudentMark]
capMarks cMarks = [capMark mark | mark <- cMarks]
Кроме того, вы также можете использовать сопоставление с образцом и явную рекурсию:
capMarks [] = []
capMarks (x:xs) = capMark x : capMarks xs
Первая строка говорит, что capMarks
применяется к пустому списку является пустым списком. Вторая строка говорит, что capMarks
применяется к списку с хотя бы одним элементом capMark
к первому элементу, а затем рекурсивно применить capMarks
к остальной части списка.
Это такой распространенный паттерн в Haskell, что есть функция map
это обобщает это. С помощью map
невероятно просто:
capMarks cMarks = map capMark cMarks
map
имеет тип (a -> b) -> [a] -> [b]
это означает, что он берет функцию и список и возвращает список. (The a
а также b
просто скажите компилятору, какие типы должны быть одинаковыми.) map
затем применяет функцию к каждому элементу в списке ввода.
Со временем вы узнаете о частичном применении функций и стиле без точек. С этими двумя понятиями версия, использующая map
можно немного упростить:
capMarks = map capMark
Пока не беспокойтесь об этом. Я просто добавляю это здесь для полноты.
Вы должны проверить, как работает сопоставление с образцом в Haskell.
capMarks [x]
будет соответствовать только список с одним элементом. То, что вы, вероятно, хотите, что-то вроде capMarks myList = [ ... | ... <- f myList]
или определить остатки дел рекурсивным способом.
Например
capMarks [] = []
capMarks x:xs = capMark x : capMarks xs
Эта упрощенная "версия" работает в объятиях
capMarks :: [Integer] -> [Integer]
capMarks xs = [(*) 2 x | x <- xs]