Функция, которая принимает параметры двух типов данных, печатает один и повторяет для следующего - PullRequest
0 голосов
/ 30 октября 2018

Я проектирую интерпретатор из моего AST, и я застрял в одной части этого, где я должен оценить и напечатать один тип данных и выполнить итерацию в списке другого.

Вот типы данных, основанные на AST.

data Match = Matching Patt Expr deriving (Eq,Show,Read)

data Rules = Ruling Match [Rules] deriving (Eq,Show,Read)

Предполагается, что функция rules оценивает Match и выполняет итерации по правилам для их печати Вот функция и то, что я попробовал без удачи

evalMatch::Match -> String
evalMatch (Matching patt expr) = evalPatt patt ++ evalExpr expr

evalRules::Rules -> Match -> [Rules] -> String
evalRules (Ruling match [rules]) = do evalMatch match 
                                  listRules [rules]
evalRules::Rules -> Match -> [Rules] -> String
evalRules (Ruling match [rules]) = do evalMatch match 
                                   listRules [rules]
                                   --also tried = evalMatch match ++ listRules [rules]

listRules::[Rules] -> String
listRules [] = []
listRules (x:xs) = show x ++ listRules xs

Я новичок в Хаскеле, и я очень благодарен за любую помощь.

Я получаю ошибку компилятора

  • Не удалось найти ожидаемый тип Match -> [Rules] -> String' with actual type [Char] '
    • В блоке блока 'do': совпадение evalMatch В выражении: сделать соответствие evalMatch listRules [правила] В уравнении для `evalRules ': evalRules (Правящий матч [правила]) = сделать соответствие evalMatch listRules [правила]

1 Ответ

0 голосов
/ 30 октября 2018

Ошибка, которую вы получаете, говорит:

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 будет работать только в том случае, если список правил содержит ровно один элемент, и в противном случае выдает исключение. Снятие скобок исправит это.

...