2016-01-22 4 views
1

Для начала я создал Type StudentMark, который является кортежем, берущим сначала строку, а во-вторых Int.Haskell List Comprehension Неисчерпывающий шаблон при вызове более одного параметра

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)] 

Но будет возвращать только правильный и ожидаемый ответ, когда я ввод только один параметр в функцию, например:

capMarks [("Jake", 50)] 

Или

capMarks [("Jake"), 30] 

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

+0

Если какая-либо из моих терминов отключена, пожалуйста, воздержитесь от меня, поскольку я новичок и для Haskell, и для stackoverflow. – MichaelAS

+0

Давайте сделаем шаг назад. Что вы пытаетесь выполнить с помощью этих функций? Какова цель этого кода? Какую проблему вы пытаетесь решить с помощью этого кода? –

+0

Предполагается вернуть кортежи, в которых значения целых чисел более 40 будут возвращены как 40 в соответствии с функцией capMark. т. е. 'capMark (« Steve », 100)' будет возвращать '(« Steve », 40)', поэтому функция capMarks должна делать это, используя функцию capMark, чтобы сделать это для списка кортежей, используя понимание списка. – MichaelAS

ответ

3

Давайте анализировать 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], который означает, что он принимает функцию и список и возвращает список. (a и b просто укажите компилятору, какие типы должны быть одинаковыми.) map затем применяет функцию к каждому элементу в списке ввода.

В конце концов вы узнаете о применении частичных функций и беспутном стиле. С этими двумя понятиями, версия с использованием map может быть упрощена немного:

capMarks = map capMark 

Не слишком беспокоиться об этом еще. Я просто добавляю его здесь для полноты.

+0

Code-Apprentice, я вижу вопрос, который у меня был сейчас! Я думал, что моя функция capMark должна быть на стороне соответствия шаблону понимания. Теперь это намного больше, спасибо. – MichaelAS

+0

@ GarethAllen-Stringer Я отредактировал свой вопрос с более подробным объяснением, включая некоторые альтернативные варианты. Надеюсь, это поможет. Удачи вам в обучении Haskell. –

+0

А я вижу, как карта работает из вашего примера. Нам еще этого не научили, но я буду помнить об этом в будущем, поскольку, похоже, он будет очень полезен. Ваша полнота высоко ценится. Я видел '(x: xs)', но не понял, что это значит и как он работает. – MichaelAS

1

Вы должны проверить, как работает шаблон в Haskell.

capMarks [x] будет соответствовать только одному элементу. То, что вы, вероятно, хотите, это что-то вроде capMarks myList = [ ... | ... <- f myList] или рекурсивно определить остатки корпусов.

Например

capMarks [] = [] 
capMarks x:xs = capMark x : capMarks xs 

Это упрощенная "версия" работает в объятиях

capMarks :: [Integer] -> [Integer] 
capMarks xs = [(*) 2 x | x <- xs] 
+0

Мой Haskell ржавый: -/ – Ale

+0

У меня есть голова вокруг большей части его, но теперь, когда он вызывает предыдущую функцию, есть много проблем, связанных с неправильным сопоставлением типов. Однако я следую вашей упрощенной версии. – MichaelAS

+0

Проблема заключается в том, что переменная cMarks представляет собой список кортежей (StudentMark), но функция capMark будет принимать только один StudentMark, а не список из них. – MichaelAS