閱讀946 返回首頁    go 技術社區[雲棲]


使用Ruby amb解決說謊者謎題

    說謊者謎題是sicp4.3.2小節的一道題目,題目本身不難:
五個女生參加一個考試,她們的家長對考試結果過分關注。為此她們約定,在給家裏寫信談到考試的時候,每個姑娘都要寫一句真話和一句假話。下麵是從她們的信裏摘抄出來的句子:
Betty : kitty考第二,我隻考了第三
Ethel : 你們應該很高興聽到我考了第一,joan第二
joan :   我考第三,可憐的Ethel墊底
kitty:  我第二,marry隻考了第四
marry: 我是第四,Betty的成績最高。
這五個姑娘的實際排名是什麼?

    Ruby本來就有call/cc,因此也可以實現amb操作符,網上已經有一個實現了:
class Amb
  
class ExhaustedError < RuntimeError; end
  def initialize
    @fail 
= proc { fail ExhaustedError, "amb tree exhausted" }
  end
  def choose(
*choices)
    prev_fail 
= @fail
    callcc { 
|sk|
      choices.each { 
|choice|
        callcc { 
|fk|
          @fail 
= proc {
            @fail 
= prev_fail
            fk.call(:fail)
          }
          
if choice.respond_to? :call
            sk.call(choice.call)
          
else
            sk.call(choice)
          end
        }
      }
      @fail.call
    }
  end
  def failure
    choose
  end
  
  def 
assert(cond)
    failure unless cond
  end
  alias :require :
assert
end

    這一段代碼與scheme宏實現amb是完全相同的:
(define amb-fail '*)

(define initialize
-amb-fail
  (
lambda ()
    (set! amb
-fail
      (
lambda ()
        (error 
"amb tree exhausted")))))

(initialize
-amb-fail)
(define call
/cc call-with-current-continuation)
(define
-syntax amb
  (syntax
-rules ()
    ((amb alt )
     (let ((prev
-amb-fail amb-fail))
       (call
/cc
        (
lambda (sk)

          (call
/cc
           (
lambda (fk)
             (set! amb
-fail
                   (
lambda ()
                     (set! amb
-fail prev-amb-fail)
                     (fk 
'fail)))
             (sk alt))) 
             
             (prev
-amb-fail)))))))
    回到謎題,從題意可知每個姑娘的兩句話的異或結果為true,並且姑娘的排名肯定不會相同,因此定義兩個輔助過程:
require 'amb'
def distinct?(items)
  items.uniq
==items
end
def xor(exp1,exp2)
 (exp1 
or exp2) and !(exp1 and exp2)
end
    剩下的完全就是將題目翻譯成代碼即可了,沒有多少可以解釋的東西:

amb=Amb.new
betty
=amb.choose(*[1,2,3,4,5])
ethel
=amb.choose(*[1,2,3,4,5])
joan
=amb.choose(*[1,2,3,4,5])
kitty
=amb.choose(*[1,2,3,4,5])
marry
=amb.choose(*[1,2,3,4,5])

amb.require(xor(kitty
==2,betty==3))
amb.require(xor(ethel
==1,joan==2))
amb.require(xor(joan
==3,ethel==5))
amb.require(xor(kitty
==2,marry==4))
amb.require(xor(marry
==4,betty==1))
amb.require(distinct?([betty,ethel,joan,kitty,marry]))
puts 
"betty:#{betty} ethel:#{ethel} joan:#{joan} kitty:#{kitty} marry:#{marry}"

    答案就是:
    betty:3 ethel:5 joan:2 kitty:1 marry:4  

    最後給出一個Prolog的解答:
notmember(A,[]).
notmember(A,[B
|L]):-
  A\
==B,
  notmember(A,L).
distinct([A,B,C,D,E]):
-
   notmember(A,[B,C,D,E]),
   notmember(B,[A,C,D,E]),
   notmember(C,[A,B,D,E]),
   notmember(D,[A,B,C,E]),
   notmember(E,[A,B,C,D]).
xor(Exp1,Exp2):
-
   (Exp1;Exp2),\
+ (Exp1,Exp2).
solve(Betty,Ethel,Joan,Kitty,Marry):
-  
   X
=[1,2,3,4,5],
   member(Betty,X),
   member(Ethel,X),
   member(Joan,X),
   member(Kitty,X),
   member(Marry,X),
   distinct([Betty,Ethel,Joan,Kitty,Marry]),
   xor(Kitty
=:=2,Betty=:=3),
   xor(Ethel
=:=1,Joan=:=2),
   xor(Joan
=:=3,Ethel=:=5),
   xor(Kitty
=:=2,Marry=:=4),
   xor(Marry
=:=4,Betty=:=1).
文章轉自莊周夢蝶  ,原文發布時間2008-11-15

最後更新:2017-05-18 11:02:08

  上一篇:go  HandlerSocket client for java——MySql as NoSQL
  下一篇:go  《Flink官方文檔》示例總覽