kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

Reasoned Schemer (111) bumpo、gen&test+o、enumerate+o、enumerateo

bumpo

(defrel (bumpo n x)
  (conde ((== n x))
         ((fresh (m) (-o n '(1) m) (bumpo m x)))))

これは問題ない

gen&test+o

(defrel (gen&test+o i j k)
  (onceo (fresh (x y z)
           (+o x y z)
           (== i x) (== j y) (== k z))))

これの意味が分からない
足してzになるxyをいっぱい作ってから
ixと同じでjyと同じでkzと同じかどうか試している
最初っからijを足したらkになるかどうか試せばいいだけじゃない?

(defrel (mygen&test+o i j k) (onceo (+o i j k)))って定義すれば

> (run* q (gen&test+o '(0 0 1) '(1 1) '(1 1 1)))
'(_0)
> (run* q (test+o '(0 0 1) '(1 1) '(1 1 1)))
'(_0)

ほら同じ、ってこれだけじゃわかんないけど

> (run 1 q (gen&test+o '(0 0 1) '(1 1) '(0 1 1)))
(no value)
> (run 1 q (mygen&test+o '(0 0 1) '(1 1) '(0 1 1)))
'()

むしろ優秀じゃね?
それとも試し続ける必要がある?

enumerate+o

(defrel (enumerate+o r n)
  (fresh (i j k)
    (bumpo n i)
    (bumpo n j)
    (+o i j k)
    (gen&test+o i j k)
    (== `(,i ,j ,k) r)))

iを列挙してjを列挙してki+jにする
これで終わりでいいんじゃないの(rは設定するとして
(gen&test+o i j k)は何してるの

(gen&test+o i j k)抜きで定義して・・・

(defrel (myenumerate+o r n)
  (fresh (i j k)
    (bumpo n i)
    (bumpo n j)
    (+o i j k)
    (== `(,i ,j ,k) r)))

実行してやると

> (run* s (myenumerate+o s '(1 1)))
'(((1 1) (1 1) (0 1 1))
  ((1 1) (0 1) (1 0 1))
  ...
  ((1) (1) (0 1))
  ((1) () (1)))

答えの出てくる順番は違うけど別にこれでもよくない?
狙いがわからない

Do we need gen&test+o (gen&test+oって必要?)
Not at all (いやまったく)

あ、そうだよねそういう流れだよね

(snip) so we can replace (gen&test+o i j k) with the onceo expression unchanged in enumerate+o.
だから、enumerate+o(gen&test+o i j k)onceoの式で置き換えられますよ

え?
(gen&test+o i j k)は削っても大丈夫って話じゃないの?

なんなのこれ

(defrel (enumerate+o r n)
  (fresh (i j k)
    (bumpo n i)
    (bumpo n j)
    (+o i j k)
    (onceo (fresh (x y z)
           (+o x y z)
           (== i x) (== j y) (== k z)))
    (== `(,i ,j ,k) r)))

最後のgoal

(defrel (enumerateo op r n)
  (fresh (i j k)
    (bumpo n i)
    (bumpo n j)
    (op i j k)
    (onceo (fresh (x y z)
           (op x y z)
           (== i x) (== j y) (== k z)))
    (== `(,i ,j ,k) r)))

上のgoalはただ+oopに置き換えやすいようにしただけなのかな
(gen&testo op i j k)みたいなの定義してもよさそうだけど

高階goal?goalを引数として渡してるのは新鮮

> (run* s (enumerateo +o s '(1 1)))
'((() (1 1) (1 1))
  ((1 1) () (1 1))
  ...  
  ((1 1) (1 1) (0 1 1))
  ((1 1) (0 1) (1 0 1)))
> (run* s (enumerateo *o s '(1 1)))
'(((0 1) (1 1) (0 1 1))
  ((1) (1 1) (1 1))
  ...
  (() () ())
  ((1 1) (1 1) (1 0 0 1)))

そもそもopが2回出てくる意味がわからないわけだが
ここから応用範囲が広がりそうな気はする
(でもReasoned Schemerではここまで)

/oとかlogoに使えるようにしたバージョン

(defrel (enumerate2o op r n)
  (fresh (i j k h)
    (bumpo n i)
    (bumpo n j)
    (op i j k h)
    (onceo (fresh (x y z w)
           (op x y z w)
           (== i x) (== j y) (== k z)))
    (== `(,i ,j ,k ,h) r)))

文字を増やしただけ

> (run* s (enumerate2o /o s '(1 1)))
'(((1) (1 1) () (1))
  (() (1 1) () ())
  ...
  ((1 1) (1) (1 1) ())
  ((0 1) (1) (0 1) ()))
> (run* s (enumerate2o logo s '(1 1)))
'(((1 1) (1 1) (1) ())
  ((1 1) () (_0 . _1) (1 1))
  ...
  ((0 1) (1) (_0 . _1) (1))
  ((0 1) (1 1) () (1)))

10章は一度読み返してるし、これで終わりでいいかな
やっぱり関係プログラミング脳になった感じはしない
大変だなあという感想
わざわざ大変なところをやったのかもしれない
Prolog勉強したら印象は違ってくるのかな
でも今はやらない