<![CDATA[Kilosecond Blog]]>2012-12-26T17:30:39-05:00http://blog.kilosecond.com/Octopress<![CDATA[Secret Santa with core.logic]]>2012-12-26T11:45:00-05:00http://blog.kilosecond.com/blog/2012/12/26/secret-santa-with-core-dot-logicOr: Writing Goals with Pattern Matching

I’d been looking for an excuse to use
core.logic for something,
and I finally created an opportunity when I wrote a Secret Santa
picker.

(Familiarize yourself with this
primer
for background on how core.logic works and looks.)

Zipping lists

At the end of running a Secret Santa program, you effectively want a
map of the people involved to the people they’re giving gifts
to. Unfortunately, working with maps isn’t straightforward in
core.logic, but lists are. I figured I’d take a list of participants
and a list of recipients and zip them together.

1234567

(defnezipo"zipped is zipped pairs of xl and yl"[xlylzipped]([()()()])([[x. xs][y. ys][z. zs]](== z[xy])(zipoxsyszs)))

Like conso, firsto, and resto, this is a goal, so the “result”
of zipping the first two arguments must be supplied as well.

In the first case (line 4), we’re saying that two empty lists zipped
together is the empty list. In the second case (line 5), we
destructure the lists into their heads and tails, saying that the
head (z) is the vector [x y], and that the tails have the same
zipped relationship.

I find that running goals on non-grounded vars can be illuminating:

Everyone’s buying for themselves! We’ll need to add a constraint
against that:

1234567

(defneno-doubleso"pairs does not have a pair with identical members"[pairs]([()])([[[ab]. ps]](!=ab)(no-doublesops)))

Once again, pattern matching. The degenerate case, the empty list
(line 4), simply succeeds. If we have a head and tail (line 5), we
destructure the head, too, so we can assert that the two members of
that vector pair are not equal.