То есть used
- это функция Term -> [Var]
. И поэтому, чтобы написать used
в стиле сопоставления с шаблоном, нам нужно подготовить кейс для каждого из различных способов быть Term
. Глядя на определение Term
, мы видим, что есть 3 способа быть Term
: быть переменной, лямбда-выражением или приложением. В частности, быть пустым списком ([]
) не является способом быть Term
, поэтому этот случай должен быть удален.
Далее давайте рассмотрим синтаксис сопоставления с образцом. Это должно выглядеть следующим образом:
used :: Term -> [Var]
used (Variable var) = ...
used (Lambda var term) = ...
used (Apply term1 term2) = ...
Обратите внимание на круглые скобки вокруг каждого набора конструктора данных и аргументов. Также обратите внимание, что переменные в Haskell должны начинаться со строчных букв. В заключение отметим, что мы на самом деле не написали ни одного из корпусов дел для used
. Вышеуказанное не является действительным Haskell.
Давайте go рассмотрим, как заполнить все правые части этих случаев. Пока мы делаем это, давайте помнить, что used
предназначен для возврата упорядоченного списка Var
без повторов. Большая часть этого не фиксируется в типе used
.
Случай Variable
:
used (Variable var) = ...
Так что правая часть здесь должна быть списком Var
. Проверяя объявление Term
и Variable
, мы видим, что var
должно быть Var
. Таким образом, на самом деле единственным вариантом реализации является:
used (Varable var) = [var]
Случай Lambda
used (Lambda var term) = ...
Итак, снова проверяя объявление типа Term
, мы видим, что var
Var
и term
Term
. Может быть, поэтому мы использовали эти имена переменных;). Таким образом, некоторые переменные появляются в var
, а некоторые переменные появляются в term
. Если бы мы знали все эти переменные, мы могли бы объединить эти результаты с merge
. Для var
мы можем сделать то же самое, что и в случае Variable
. Для term
нам нужен способ превратить Term
в переменную или список переменных. К счастью, у нас есть такой способ. Это функция, которую мы сейчас определяем: used
! Таким образом, мы можем записать этот случай как:
used (Lambda var term) = merge [var] (used term)
Может показаться немного глупым использовать merge
для объединения одноэлементного списка в другой список, но нам нужно сохранить результат в порядке, а merge
- это молоток, который у нас есть, поэтому мы превратили эту проблему в гвоздь.
* * * * * * * * * * * * * * * * * * * * * '' * '' *. У нас есть used (Apply term1 term2) = ...
term1
и term2
Term
. Мы извлечем переменные из каждой из них, используя used
, и объединим их вместе, используя merge
. used (Apply term1 term2) = merge (used term1) (used term2)
В целом это дает реализацию used
: used :: Term -> [Var]
used (Variable var) = [var]
used (Lambda var term) = merge [var] (used term)
used (Apply term1 term2) = merge (used term1) (used term2)
с *Main> used example
["a","b","x","y"]
по желанию.