defne
- это макрос, который использует специальный синтаксис сопоставления с образцом, но ведет себя подобно conde
. (К вашему сведению e
в каждом из них означает «все», то есть каждый пункт может внести свой вклад.)
- Подчеркивание
_
указывает значение, которое должно присутствовать, но вам все равно, что это такое.
-
.
указывает на объединение элементов слева от .
и хвост списка справа от .
. Это используется для привязки как отдельных элементов списка, так и остальной части списка к различным значениям. (Также см. llist
в core.logic.)
Аналогичная деструктуризация последовательности в Clojure будет использовать &
вместо .
:
(let [[_ _ [_ & tail]] coll] ...)
Таким образом, следующий шаблон означает: «нас не волнует первый или второй входной аргумент, но третий должен быть списком, в котором наша голова равна x
(т.е. равна x
входному аргументу функции) и привязать хвост к tail
":
[_ _ [x . tail]]
Также обратите внимание, что tail
может быть здесь пустым списком, и вы можете связать более одного значения до .
.
Поскольку ваш пример является рекурсивной целью, он в конечном итоге завершится, либо найдя x
до y
, либо не сможет соответствовать ни одному из шаблонов, поскольку l
будет (в конце концов) пустым списком ()
, который не будет соответствовать ни одному случаю.
Более простой пример
Само определение membero
является более простым примером той же идеи:
(defne membero
"A relation where l is a collection, such that l contains x."
[x l]
([_ [x . tail]])
([_ [head . tail]]
(membero x tail)))
Есть два предложения, каждое из которых представлено списком верхнего уровня ()
:
[_ [x . tail]]
- Первый _
представляет собой ввод x
arg, который нам не нужен, чтобы соответствовал on [x . tail]
описывает шаблон для второго аргумента l
, где, если x
является заголовком l
, то этот шаблон совпадает и membero
успешно.
[_ [head . tail]
- _
означает здесь то же самое. Но обратите внимание, мы дали новое имя главе l
, который должен быть непустым списком, чтобы соответствовать этому шаблону. Если он совпадает, то мы продолжаем поиск с (membero x tail)
.
Только первое предложение может сделать цель успешной, найдя x
в (под) списке l
; второй пункт используется только для деструктуры head
и tail
из l
и рекурсии.
Вот membero
переведено с conde
и без сопоставления с шаблоном:
(defn memberoo [x l]
(conde
[(fresh [a d]
(conso a d l)
(== a x))]
[(fresh [a d]
(conso a d l)
(memberoo x d))]))