I'm trying it with this TXR Lisp, just for fun. It uses an implementation of John MacCarthy's amb operator based on delimited continuations, which are slow. (defmacro amb-scope (. forms)
^(block amb-scope ,*forms))
(defun amb (. args)
(suspend amb-scope cont
(each ((a args))
(whenlet ((res (and a (call cont a))))
(return-from amb-scope res)))))
(defmacro 0-9 () '(amb 0 1 2 3 4 5 6 7 8 9))
(defmacro val (p q r) ^(+ (* 100 ,p) (* 10 ,q) ,r))
(compile-only
(amb-scope
(let* ((A (0-9)) (B (0-9)) (C (0-9))
(D (0-9)) (E (0-9)) (F (0-9))
(G (0-9)) (H (0-9)) (I (0-9))
(J (0-9)))
(amb (and (eql (+ (val A B C)
(val D E F)
(val G H I))
(+ 1230 J))
(eql 1023 (mask A B C D E F G H I J))))
(prinl (list A B C D E F G H I J)))))
Every amb expression says: "I denote my leftmost non-nil argument which makes the remaining computation successful".The "remaining computation" is the future computation up to returning a value from the enclosing amb-scope form. The amb-scope form succeeds if it yields a non-nil value. We use amb to ambiguously bind A, B, C, ... to all the values from 0 to 9, amb magically selects the successful value for each one. We also use amb to express assertions. If we assert (amb (eq 'day 'night)) then that fails: night is not day. We simply assert the desired conditions over the variables. If there is any way for the conditions to be true, then that means there exist successful values for the variables and so all the prior ambs choose those successful values. This is the TXR Lisp interactive listener of TXR 272.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
Upgrade to TXR Pro for a one-time fee of learning Lisp!
1> (compile-file "abcprob")
t
2> (load "abcprob")
(0 1 2 3 4 5 8 7 9 6)
nil
Thus 012
345
879
----
1236
The "all letter digits unique" is efficiently met using bits to represent a set. TXR Lisp has a mask function which calculates an integer whose binary representation has a 1 in the positions indicated by the arguments. E.g (mask 0 2) yields 6, and (mask 0 1 2) yields 7.If mask is given 10 unique digit values---the complete set---it must produce the value #b1111111111 or 1023, the complete set mask. We thereby avoid n squared silliness like (and (neql A B) (neql A C) ...): asserting that no letter pair is equal. |