20-CS-4003-001 Organization of Programming Languages Fall 2017
Call-with-current-continuation examples

Lambda calculus, Type theory, Formal semantics, Program analysis

    Prev     Next     All lectures        Code

The Kalotan Puzzle

;;; Implementation of amb
;;;
(define call/cc call-with-current-continuation)

(define amb-fail (lambda () (error 'no-solution)))

(define-syntax amb
  (syntax-rules ()
    ((amb x ...)
     (let ((prev-level amb-fail))
       (call/cc
         (lambda (sk)
           (call/cc
             (lambda (fk)
               (set! amb-fail (lambda () (fk 'fail)))
	            (sk x)))
           ...
           (prev-level)))))))

;; Required Helper Procedures -
;; (assert pred) - forces pred to be true
;;
(define assert (lambda (p) (if (not p) (amb))))

;; -------------------------------------------------
;; code above this line is applicable to
;; many problems

;; (xor p1 p2) - p1 and not p2 or not p1 and p2
;;
(define xor
  (lambda (p1 p2)
    (or (and (not p1) p2) (and p1 (not p2)))))

;; Solution to the puzzle using "amb"
;;
(define puzzle
  (lambda ()
    (let ((parent1 (amb 'male 'female))
          (parent2 (amb 'male 'female))
          (kid (amb 'male 'female))
          (kid-said (amb 'male 'female))
          (kid-lied (amb #t #f)))

      (assert (not (eq? parent1 parent2)))
      (assert (xor (eq? kid-said kid) kid-lied))
      (assert (if (eq? parent1 'female)
                  (and (eq? kid-said 'female)
                       (xor (eq? kid 'male) kid-lied))
                  (and (eq? kid 'male) kid-lied)))

      (list 'Parent 1 'is 'a parent1
            '- 'Parent 2 'is 'a parent2
            '- 'Kid 'is 'a kid))))
 -  A solution to the Kaloton Puzzle. The Kalotans are a tribe with two peculiar quirks: first, their females always tell the truth and their males never make two consecutive true statements, or two consecutive untrue statements; second, non-kalotans cannot distinguish males from females. An anthropologist (let's call him Worf) has begun to study them. Worf does not yet know the Kalotan language. One day, he meets a Kalotan (heterosexual) couple and their child Kibi (also called "kid"). Worf asks the kid: Are you a boy? The kid answers in Kalotan, which of course Worf doesn't understand.

Worf turns to the parents (who know English) for an explanation. One of them (parent1) says: "Kibi said: I am a girl." The other (parent2) adds: "Kibi is a boy. Kibi lied."

The puzzle is to find the sex of the parents and Kibi.

Procedure puzzle sets up the solution. It has three parts. In the let, all possible values are listed for all variables via amb statements. The variables kid, parent1, and parent2 will answer the question of sex so their possible values are 'male and 'female. The solution depends on the kid's response which is value of the variable kid-said. The possible values are 'male and 'female. Lastly a variable kid-lied? is declared and takes value #t or #f.

The second part is the set of assertions which, if satisfied for some assignment of values to the above variables, imply a solution. There are three assertions shown. The first one requires the couple to be heterosexual. The second defines the meaning of kid-lied. The third says if parent1 is the female, then Kibi must have said she is a female and, from the response of parent2 (the male) either Kibi is a male or Kibi lied, but if parent1 is the male, then the response of parent2 (the female) implies Kibi is a male and he lied.

The last part is a list of variable values which is returned by puzzle as the solution to the problem.

Statements that print the return value of continuations, when they are invoked, were added to the code. The line

   (display 'up)(newline)
was inserted just before (fk 'fail) and
   (display 'next:)(display x)(display " ")
was inserted just before (sk x). In addition lines such as
   (display 'assertion-1-success)(newline)
were added after every assertion to identify which fail on which values. The result was the following:
next:#t next:male next:male next:male next:male up
next:female assertion-1-success
up
up
next:female next:male assertion-1-success
up
next:female up
up
up
next:female next:male next:male up
next:female assertion-1-success
assertion-2-success
assertion-3-success
assertion-4-success
assertion-5-success
;Value 13: (parent 1 is a female - 
            parent 2 is a male - 
            kid is a female)
The first line shows the order in which variables are assigned values: from kid-lied? to parent1. Since parent1 and parent2 are equal the first assertion was no satisfied causing fk to be invoked (showing up). Then parent1 was changed to female. Assertion 1 succeeded by assertion 2 did not. Then fk was invoked twice - once because there are no more values to try for parent1 and once to back up one level and change the value for parent2 to female. Then parent1 starts over with male, which satisfies assertion 1 but not 2. So parent1 is changed to female which violates assertion 1 and causes three invocations of fk and results in kid getting value female, and parent2 and parent1 getting value male. That violates assertion 1 so fk is invoked and parent1 is set to female. At that point all assertions are satisfied and the problem is solved.