I was trying to understand a custom core.logic
constraint as defined below,
(defne lefto
"x appears to the left of y in collection l."
[x y l]
([_ _ [x . tail]] (membero y tail))
([_ _ [_ . tail]] (lefto x y tail)))
How to interpret _
and .
in the context of core.logic
?
defne
is a macro that uses a special pattern matching syntax, but behaves similarly toconde
. (FYI thee
in each of these stands for "everything" i.e. every clause can contribute.)_
underscores indicate a value that must be present, but you don't care what it is..
indicates a concatenation of items to the left of.
and the tail of the list to the right of.
. This is used to bind both individual items of a list and the remainder of the list to different values. (Also seellist
in core.logic.)A similar destructuring of a sequence in Clojure would use
&
instead of.
:So the following pattern means "we don't care about the first or second input argument, but the third should be a list where we the head is
x
(i.e. equal to the function'sx
input argument) and bind the tail totail
":Also note that
tail
can be the empty list here, and you can bind more than one value before the.
.Since your example is a recursive goal, it will eventually terminate by either finding
x
beforey
, or it will fail to match either pattern becausel
will (eventually) be the empty list()
which won't match either case.Simpler example
The
membero
definition itself is a simpler example of the same idea:There are two clauses, each represented by a top-level list
()
:[_ [x . tail]]
- The first_
represents the inputx
arg we don't care to match on. The[x . tail]
describes a pattern for the second argumentl
where ifx
is the head ofl
, then this pattern matches andmembero
succeeds.[_ [head . tail]
- The_
means the same thing here. But notice we've given a new name to the head ofl
, which only needs to be a non-empty list to satisfy this pattern. If it matches, then we recurse with(membero x tail)
to continue searching.Only the first clause can make the goal successful, by finding
x
in a (sub)list ofl
; the second clause is only used to destructure thehead
andtail
ofl
and recurse.Here's
membero
translated withconde
and no pattern matching: