Wednesday, July 03, 2013

Getting my feet wet with Clojure's core.logic

Yesterday I read a nice article about implementing Event Sourcing in Clojure. The domain that the author had chosen to illustrate the concept was the rock-paper-scissors game. The compare-moves multimethod seemed a bit ugly to me, so I thought it would be a great opportunity to try logic programming in Clojure. Here is what I did:

1. Create a new Clojure project using Leiningen:
2. Add clojure.core.logic to project dependencies list:
3. Tell Leiningen to install the dependencies:
4. Write the rules of the rock-paper-scissors game in src/rock_paper_scissors/core.clj:
5. Start a REPL and play a little:
I hope you enjoy the declarative style! I surely do and will certainly continue my exploration of the awesome world of logic programming.

2 comments:

Will Byrd said...

Time to run the program backwards, and generate games of RPS. :)

Inushi Wolf said...

This was fun.

When trying to follow along, I found that clojure.core.logic has deprecated "defrel" and "fact" in favor of new syntax. I got it working with the following, using pldb/db-rel and pldb/with-db:

(ns rock-paper-scissors.core
(:refer-clojure :exclude [==])
(:require [clojure.core.logic.pldb :as pldb]
[clojure.core.logic :refer :all]))

(pldb/db-rel beats hand1 hand2)
(def facts
(pldb/db
[beats :rock :scissor]
[beats :paper :rock]
[beats :scissor :paper]))

(defn play [hand1 hand2]
(pldb/with-db facts
(doall
(run* [result]
(conde
((beats hand1 hand2) (== result :victory))
((beats hand2 hand1) (== result :loss))
((== hand1 hand2) (== result :tie)))))))