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?
defneis a macro that uses a special pattern matching syntax, but behaves similarly toconde. (FYI theein 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 seellistin 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'sxinput argument) and bind the tail totail":Also note that
tailcan 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
xbeforey, or it will fail to match either pattern becauselwill (eventually) be the empty list()which won't match either case.Simpler example
The
memberodefinition 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 inputxarg we don't care to match on. The[x . tail]describes a pattern for the second argumentlwhere ifxis the head ofl, then this pattern matches andmemberosucceeds.[_ [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
xin a (sub)list ofl; the second clause is only used to destructure theheadandtailofland recurse.Here's
memberotranslated withcondeand no pattern matching: