Ошибка, которую вы получаете, говорит:
Couldn't match expected type `Match -> [Rules] -> String' with actual type `[Char]'
Это говорит о том, что не так: ожидаемый тип evalRules
равен Rules -> Match -> [Rules] -> String
(это соответствует подписи типа, которую вы написали), но фактический тип функции в том виде, как он реализован, равен Rules -> [Char]
(или эквивалентно Rules -> String
). Другими словами, ваша сигнатура типа утверждает, что функция должна принимать три аргумента, но ваша реализация принимает только один:
evalRules :: Rules -> Match -> [Rules] -> String -- three arguments
evalRules (Ruling match [rules]) = ... -- (Ruling match [rules]) is one argument of type `Rules`
Вам нужно будет либо добавить два других аргумента в вашу реализацию, либо удалить их из сигнатуры вашего типа. Из того, что я могу сказать, вы, вероятно, хотите последнее.
Есть и другие проблемы с этим кодом:
сделать запись
При использовании обозначения do
действия должны иметь правильный отступ, чтобы они выстраивались в ряд:
-- incorrect
evalRules (Ruling match [rules]) = do evalMatch match
listRules [rules]
-- correct
evalRules (Ruling match [rules]) = do evalMatch match
listRules [rules]
-- also correct
evalRules (Ruling match [rules]) = do
evalMatch match
listRules [rules]
Как видите, звонки на номера evalMatch
и listRules
должны начинаться в одном столбце. В противном случае вы получите ошибки разбора.
Монада
Вы можете использовать do
блоки только в контексте монад. Монада - это любой тип, который реализует класс типов Monad
, например IO
или Maybe
. Допустим, вы создаете действие IO
: в этом случае ваша функция должна возвращать тип IO <something>
, а каждое действие в блоке do
должно иметь тип IO <something>
. Но ваш evalRules
возвращает тип String
, и каждое действие в блоке do
также имеет тип String
. Здесь нет монадического контекста.
(Как выясняется, String
эквивалентно [Char]
, а [<something>]
- это монада, так что ваша функция как есть будет проверять тип ... но она, вероятно, не будет вести себя так, как вы ожидаете. )
Прямо сейчас вызов evalMatch
в этом блоке do
, похоже, ничего не делает (он возвращает результат String
, который быстро игнорируется). Если вы хотите вернуть результат String
из него вместе с результатом из listRules
, вы можете использовать оператор ++
для объединения строк вместо блока do
. Итак, ваш комментарий здесь - правильная реализация:
--also tried = evalMatch match ++ listRules [rules]
Списки в шаблонах
Вы используете шаблон (Ruling match [rules])
, который не делает то, о чем вы, вероятно, думаете. При сопоставлении списка у вас есть следующие опции:
(Ruling match [])
соответствует пустому списку по второму аргументу Ruling
.
(Ruling match (r:rs))
соответствует непустому списку, связывая первый элемент с r
, а остальную часть списка с rs
.
(Ruling match [rule1, rule2, rule3])
соответствует списку точно с тремя элементами и связывает каждый элемент с rule1
, rule2
и rule3
соответственно.
(Ruling match [rule1])
соответствует списку с ровно одним элементом и связывает этот элемент с rule1
.
(Ruling match rules)
соответствует любому списку и связывает список с rules
. Это, вероятно, то, что вы хотите.
Как есть, evalRules
будет работать только в том случае, если список правил содержит ровно один элемент, и в противном случае выдает исключение. Снятие скобок исправит это.