#lang racket |
|
;; solving the missionaries-and-cannibals problem with Redex |
|
(require redex) |
|
;; ----------------------------------------------------------------------------- |
;; the problem space syntax |
|
(define-language MC |
(configuration ::= (population boat population)) |
(population ::= (mc ...)) |
(boat ::= L R) |
(mc ::= c m)) |
|
;; ----------------------------------------------------------------------------- |
;; constraints |
|
(define-metafunction MC |
ok : population -> boolean |
[(ok (mc ...)) |
,(let ((m (for/sum ((mc (term (mc ...))) #:when (eq? 'm mc)) 1)) |
(c (for/sum ((mc (term (mc ...))) #:when (eq? 'c mc)) 1))) |
(or (zero? m) (>= m c)))]) |
|
;; a subject reduction test (which sadly failed for the first draft) |
(define-metafunction MC |
ok-state : configuration -> boolean |
[(ok-state ((mc_l ...) any (mc_r ...))) |
,(and (term (ok (mc_l ...))) (term (ok (mc_r ...))))]) |
|
;; ----------------------------------------------------------------------------- |
;; a reduction relation that searches the state space |
|
(define mc--> |
(reduction-relation |
MC |
(--> [(mc_l1 ... mc_* mc_l2 ... mc_+ mc_l3 ...) L (mc_r ...)] |
;; move two people from left to right |
[(mc_l1 ... mc_l2 ... mc_l3 ...) R (mc_* mc_+ mc_r ...)] |
(where population_left (mc_l1 ... mc_l2 ... mc_l3 ...)) |
(where population_right (mc_* mc_+ mc_r ...)) |
(where #true (ok population_left)) |
(where #true (ok population_right)) |
move-2-left-to-right) |
(--> [(mc mc_1 ...) R (mc_r1 ... mc_* mc_r2 ...)] |
;; move one person from right to left |
[(mc_* mc mc_1 ...) L (mc_r1 ... mc_r2 ...)] |
(where population_left (mc_* mc mc_1 ...)) |
(where population_right (mc_r1 ... mc_r2 ...)) |
(where #true (ok population_left)) |
(where #true (ok population_right)) |
move-1-right-to-left) |
(--> [(mc mc_1 ...) R (mc_r1 ... mc_* mc_r2 ... mc_+ mc_r3 ...)] |
;; move two people from right to left |
[(mc_* mc_+ mc mc_1 ...) L (mc_r1 ... mc_r2 ... mc_r3 ...)] |
(where population_left (mc_* mc_+ mc mc_1 ...)) |
(where population_right (mc_r1 ... mc_r2 ... mc_r3 ...)) |
(where #true (ok population_left)) |
(where #true (ok population_right)) |
move-2-right-to-left))) |
|
;; ----------------------------------------------------------------------------- |
(module+ main |
(traces mc--> (term ((m m m c c c) L ())) |
#:pred (lambda (e) (term (ok-state ,e))))) |
|