SAN値 Prolog (ver.2)マニュアル
last update: 2012/APR/24
たけおか (竹岡尚三)
|
|
SAN値 Prologは、たけおかが考案した、SAN値論理に基づく論理型言語である。
a) SAN値論理とは
SAN値とは「頭の正気度」を表す数値である。
SAN値が0だと、完全に気が狂っている。
述語論理に「SAN値」というものを導入する。
SAN値論理では、評価時の「頭のおかしさ具合」を「SAN値」と呼ぶ。
各事実(節)ごとに、「SAN度」を設定できる。
評価時にその時点のSAN値に、もっとも近いSAN度を持つ節が選ばれる。
SAN度を持つ述語の節は評価された後、その結果が真であったら、他の節とSAN度が比較される。
よって、SAN度を持つ述語の節はすべて評価される。
評価は、純粋な一階述語論理により行われる。よって、SAN度の付く節は、従来のpure Prologのような評価の順序に依存したプログラミングを行ってはいけない。
90:partner(ニャル子). ←SAN値が90ぐらいで選ばれる 60:partner(クー子). ←SAN値が60ぐらいで選ばれる 30:partner(ハス太). ←SAN値が30ぐらいで選ばれる論理式もOK
%%足し算が、正常にできるか? 90:plus(*X, *Y, *Z) :- *Z = *X + *Y . ←SAN値が90ぐらいで選ばれる 60:plus(*X, *Y, *Z) :- *Z1 = *X + *Y, *Z = *Z1 +1 . ←SAN値が60ぐらいで選ばれる 30:plus(*X, *Y, *Z) :- *Z = *X × *Y . ←SAN値が30ぐらいで選ばれる
SAN値Prologでは、SAN度を表す数値を、節の先頭に付ける。
ただし、通常のPure Prologと同様の実行を期待する述語では、節の先頭に T を付ける。
これによって、通常のPrologのプログラムを正常に実行することが可能である。
本SAN値PrologはLispで記述しているので、述語、節、データはLispに準じ て、すべてS式である。
append([],*x,*x). append([*a|*x], *y, [*a|*z]) :- append(*x,*y,*z).以下のように書く(S式に変形した後、節の先頭に T を付加する)
((T append () *x *x))
((T append (*a . *x) *y (*a . *z)) (append *x *y *z))))
%%足し算が、正常にできるか? 90:plus(*X, *Y, *Z) :- *Z = *X + *Y . 60:plus(*X, *Y, *Z) :- *Z1 = *X + *Y, *Z = *Z1 +1 . 30:plus(*X, *Y, *Z) :- *Z = *X × *Y .は、下のように書く
((90 plus *x *y *z)(+ *x *y *z)) ((60 plus *x *y *z)(+ *x *y *z1)(+ *z1 1 *z)) ((30 plus *x *y *z)(mul *x *y *z))
事実データベースは、複数の節を一つにリストにしたものである。
節は、ヘッドと複数のボディを一つのリストにしたものである。
節であるリストの先頭の項がヘッドで、それに続く項の列がボディである。
((t append (*a . *x) *y (*a . *z)) (append *x *y *z))
(((t append () *x *x)) ((t append (*a . *x) *y (*a . *z)) (append *x *y *z)) )
(pro-assert-new '( ((t append () *x *x)) ((t append (*a . *x) *y (*a . *z)) (append *x *y *z)) ))として、データベースに登録することができる。 これは、すなわち一度に複数の節をアサートすることである。
SAN値が90あたりで、((90 foo "(」・ω・)」うー"))が選択され、
SAN値が60あたりで、((60 foo "(/・ω・)/にゃー!"))が選択される。
SAN値が30あたりで、((30 foo "xxx" ))))が選択される。
%% Prolog的記述
90:foo("(」・ω・)」うー").
60:foo("(/・ω・)/にゃー!").
30:foo("xxx").
;; 本SAN値Prologでのプログラム
(pro-assert-new
'(
((90 foo "(」・ω・)」うー"))
((60 foo "(/・ω・)/にゃー!"))
((30 foo "xxx" ))))
SAN値が90あたりで、正常な加算を行う節が選択され、
SAN値が60あたりで、通常より1多く加える節が選択される。
SAN値が30あたりで、2つの引数を乗算する節が選択される。
%% Prolog的記述
90:plus(*x,*y,*z) :- *z = *x + *y.
60:plus(*x,*y,*z) :- *z1 = *x + *y, *z = *z1 + 1.
30:plus(*x,*y,*z) :- *z = mul(*x , *y) .
;; 本SAN値Prologでのプログラム
(pro-assert-new
'(
((90 plus *x *y *z)(+ *x *y *z))
((60 plus *x *y *z)(+ *x *y *z1)(+ *z1 1 *z))
((30 plus *x *y *z)(mul *x *y *z))))
%% Prolog的記述
fa(0,1).
fa(*n,*x):- *n1 = *n - 1 ,fa(*n1,*x1), *x = *x1 * *n.
;; 本SAN値Prologでのプログラム(意味的には通常Prologのプログラム)
(pro-assert-new
'(
((t fa 0 1))
((t fa *n *x) (- *n 1 *n1)(fa *n1 *x1)(mul *x1 *n *x))))
パズル「ハノイの塔」を解く、通常 Pure Prologプログラム。
%% Prolog的記述
hanoi(1,*f,*t,*v):-prin1(*f),prin1('->'),prin1(*t).
hanoi(*n,*f,*t,*v):-
*n1= *n - 1,
hanoi(*n1,*f,*v,*t),
hanoi(1,*f,*t,*v),
hanoi(*n1,*v,*t,*f).
;; 本SAN値Prologでのプログラム(意味的には通常Prologのプログラム)
(pro-assert-new
'(((t hanoi 1 *f *t *v) (prin1 *f)(prin1 ->)(print *t))
((t hanoi *n *f *t *v)
(- *n 1 *n1)
(hanoi *n1 *f *v *t)
(hanoi 1 *f *t *v)
(hanoi *n1 *v *t *f))))
;; 本SAN値
(pro-assert-new
'(
((t foo) (sanchi *x)(print *x))
((t bar *x)(set-sanchi *x)(foo))))
This is SBCL 1.0.50.0.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* (load "sanchi-pro.lsp") ;;; 本処理系のロード
T
* (sanchi-pro) ;;;処理系の起動
;;;;;;;;;;;; うーにゃー の例 ;;;;;;;;;;;;;;;
にゃ?-(pro-assert-new
'(
((90 foo "(」・ω・)」うー"))
((60 foo "(/・ω・)/にゃー!"))
((30 foo "xxx" ))))
SAN値=90
lisp value=(((90 FOO "(」・ω・)」うー")) ((60 FOO "(/・ω・)/にゃー!")) ((30 FOO "xxx"))
((T + *X *Y *Z) (*SYSTEM-FUNC* PRO+ *X *Y *Z))
((T - *X *Y *Z) (*SYSTEM-FUNC* PRO- *X *Y *Z))
((T MUL *X *Y *Z) (*SYSTEM-FUNC* PRO* *X *Y *Z))
((T / *X *Y *Z) (*SYSTEM-FUNC* PRO/ *X *Y *Z))
((T < *X *Y) (*SYSTEM* < '*X '*Y))
((T <= *X *Y) (*SYSTEM* <= '*X '*Y))
((T =< *X *Y) (*SYSTEM* <= '*X '*Y))
((T > *X *Y) (*SYSTEM* > '*X '*Y))
((T >= *X *Y) (*SYSTEM* >= '*X '*Y)) ((T == *X *X))
((T READ *Z) (*SYSTEM-FUNC* PRO_READ *Z))
((T PRINT *X) (*SYSTEM* PROGN (FORMAT T "~s~%" '*X) T))
((T PRIN1 *X) (*SYSTEM* PROGN (FORMAT T "~s" '*X) T))
((T TERPRI) (*SYSTEM* PROGN (FORMAT T "~%") T)))
にゃ?-(set-sanchi 90) ;;; SAN値を90にセット
SAN値=90
lisp value=90
にゃ?-((foo *x)) ;;; うーにゃーの実行
SAN値=90
- new-head=(FOO "(」・ω・)」うー") sanchi=90
- choiced-clause=((90 FOO "(」・ω・)」うー")) ;;; SAN度90の節が選ばれた
- new-head=(FOO "(/・ω・)/にゃー!") sanchi=60
- new-head=(FOO "xxx") sanchi=30
result=T
reduced-goal=((FOO "(」・ω・)」うー")) ;;; 最終的に「うー」が選ばれた
にゃ?-(set-sanchi 65) ;;; SAN値を65にセット
SAN値=90
lisp value=65
にゃ?-((foo *x)) ;;; うーにゃーの実行
SAN値=65
- new-head=(FOO "(」・ω・)」うー") sanchi=90
- choiced-clause=((90 FOO "(」・ω・)」うー")) ;;; まず、SAN度90の節が選ばれた
- new-head=(FOO "(/・ω・)/にゃー!") sanchi=60
- choiced-clause=((60 FOO "(/・ω・)/にゃー!")) ;;; SAN度がSAN値(65)に、より近い60の節が選ばれた
- new-head=(FOO "xxx") sanchi=30
result=T
reduced-goal=((FOO "(/・ω・)/にゃー!")) ;;; 最終的に「にゃー」が選ばれた
にゃ?-(set-sanchi 25) ;;; SAN値を25にセット
SAN値=65
lisp value=25
にゃ?-((foo *x)) ;;; うーにゃーの実行
SAN値=25
- new-head=(FOO "(」・ω・)」うー") sanchi=90
- choiced-clause=((90 FOO "(」・ω・)」うー")) ;;; まず、SAN度90の節が選ばれた
- new-head=(FOO "(/・ω・)/にゃー!") sanchi=60
- choiced-clause=((60 FOO "(/・ω・)/にゃー!")) ;;; SAN度がSAN値に、より近い60の節が選ばれた
- new-head=(FOO "xxx") sanchi=30
- choiced-clause=((30 FOO "xxx")) ;;; 最終的に、SAN度がSAN値(25)に、もっとも近い30の節が選ばれた
result=T
reduced-goal=((FOO "xxx")) ;;; 最終的に"xxx"が選ばれた
;;;;;;;;;;;; 足し算できるかな の例 ;;;;;;;;;;;;;;;
にゃ?-(pro-assert-new
'(
((90 plus *x *y *z)(+ *x *y *z))
((60 plus *x *y *z)(+ *x *y *z1)(+ *z1 1 *z))
((30 plus *x *y *z)(mul *x *y *z))))
SAN値=25
lisp value=(((90 PLUS *X *Y *Z) (+ *X *Y *Z))
((60 PLUS *X *Y *Z) (+ *X *Y *Z1) (+ *Z1 1 *Z))
((30 PLUS *X *Y *Z) (MUL *X *Y *Z))
((T + *X *Y *Z) (*SYSTEM-FUNC* PRO+ *X *Y *Z))
((T - *X *Y *Z) (*SYSTEM-FUNC* PRO- *X *Y *Z))
((T MUL *X *Y *Z) (*SYSTEM-FUNC* PRO* *X *Y *Z))
((T / *X *Y *Z) (*SYSTEM-FUNC* PRO/ *X *Y *Z))
((T < *X *Y) (*SYSTEM* < '*X '*Y))
((T <= *X *Y) (*SYSTEM* <= '*X '*Y))
((T =< *X *Y) (*SYSTEM* <= '*X '*Y))
((T > *X *Y) (*SYSTEM* > '*X '*Y))
((T >= *X *Y) (*SYSTEM* >= '*X '*Y)) ((T == *X *X))
((T READ *Z) (*SYSTEM-FUNC* PRO_READ *Z))
((T PRINT *X) (*SYSTEM* PROGN (FORMAT T "~s~%" '*X) T))
((T PRIN1 *X) (*SYSTEM* PROGN (FORMAT T "~s" '*X) T))
((T TERPRI) (*SYSTEM* PROGN (FORMAT T "~%") T)))
にゃ?-(set-sanchi 90) ;;; SAN値を90にセット
SAN値=25
lisp value=90
にゃ?-((plus 2 4 *x)) ;;; 2+4=? の実行
SAN値=90
- new-head=(PLUS *X *Y *Z) sanchi=90
- choiced-clause=((90 PLUS 2 4 6) (+ 2 4 6)) ;;; SAN度90の節が選ばれた
- new-head=(PLUS *X *Y *Z) sanchi=60
- new-head=(PLUS *X *Y *Z) sanchi=30
result=T
reduced-goal=((PLUS 2 4 6)) ;;; 最終的に正しい加算が選ばれた
にゃ?-(set-sanchi 65) ;;; SAN値を65にセット
SAN値=90
lisp value=65
にゃ?-((plus 2 4 *x)) ;;; 2+4=? の実行
SAN値=65
- new-head=(PLUS *X *Y *Z) sanchi=90
- choiced-clause=((90 PLUS 2 4 6) (+ 2 4 6)) ;;; まず、SAN度90の節が選ばれた
- new-head=(PLUS *X *Y *Z) sanchi=60
- choiced-clause=((60 PLUS 2 4 7) (+ 2 4 6) (+ 6 1 7)) ;;; SAN度がSAN値に、より近い60の節が選ばれた
- new-head=(PLUS *X *Y *Z) sanchi=30
result=T
reduced-goal=((PLUS 2 4 7)) ;;; 最終的に2+4=7、すなわちSAN値60の節が選ばれた
にゃ?-(set-sanchi 25) ;;; SAN値を25にセット
SAN値=65
lisp value=25
にゃ?-((plus 2 4 *x)) ;;; 2+4=? の実行
SAN値=25
- new-head=(PLUS *X *Y *Z) sanchi=90
- choiced-clause=((90 PLUS 2 4 6) (+ 2 4 6)) ;;; まず、SAN度90の節が選ばれた
- new-head=(PLUS *X *Y *Z) sanchi=60
- choiced-clause=((60 PLUS 2 4 7) (+ 2 4 6) (+ 6 1 7)) ;;; SAN度がSAN値に、より近い60の節が選ばれた
- new-head=(PLUS *X *Y *Z) sanchi=30
- choiced-clause=((30 PLUS 2 4 8) (MUL 2 4 8)) ;;; 最終的に、SAN度がSAN値(25)に、もっとも近い30の節が選ばれた
result=T
reduced-goal=((PLUS 2 4 8)) ;;; 最終的に2*4=8、を実行した節(SAN度30)が選ばれた
;;;;;;;;;;;; 普通のハノイの塔 の例 ;;;;;;;;;;;;;;;
にゃ?-(pro-assert-new
'(
((t hanoi 1 *f *t *v) (prin1 *f)(prin1 ->)(print *t))
((t hanoi *n *f *t *v) (- *n 1 *n1)
(hanoi *n1 *f *v *t)
(hanoi 1 *f *t *v)
(hanoi *n1 *v *t *f))))
SAN値=25
lisp value=(((T HANOI 1 *F *T *V) (PRIN1 *F) (PRIN1 ->) (PRINT *T))
((T HANOI *N *F *T *V) (- *N 1 *N1) (HANOI *N1 *F *V *T)
(HANOI 1 *F *T *V) (HANOI *N1 *V *T *F))
((T + *X *Y *Z) (*SYSTEM-FUNC* PRO+ *X *Y *Z))
((T - *X *Y *Z) (*SYSTEM-FUNC* PRO- *X *Y *Z))
((T MUL *X *Y *Z) (*SYSTEM-FUNC* PRO* *X *Y *Z))
((T / *X *Y *Z) (*SYSTEM-FUNC* PRO/ *X *Y *Z))
((T < *X *Y) (*SYSTEM* < '*X '*Y))
((T <= *X *Y) (*SYSTEM* <= '*X '*Y))
((T =< *X *Y) (*SYSTEM* <= '*X '*Y))
((T > *X *Y) (*SYSTEM* > '*X '*Y))
((T >= *X *Y) (*SYSTEM* >= '*X '*Y)) ((T == *X *X))
((T READ *Z) (*SYSTEM-FUNC* PRO_READ *Z))
((T PRINT *X) (*SYSTEM* PROGN (FORMAT T "~s~%" '*X) T))
((T PRIN1 *X) (*SYSTEM* PROGN (FORMAT T "~s" '*X) T))
((T TERPRI) (*SYSTEM* PROGN (FORMAT T "~%") T)))
にゃ?-((hanoi 3 a b via)) ;;; ハノイの実行
SAN値=25
A->B
A->VIA
B->VIA
A->B
VIA->A
VIA->B
A->B
result=T
reduced-goal=((HANOI 3 A B VIA))
にゃ?-
;;; Prologの終了は「end」を入力する
にゃ?-end
SAN値=25
T
*
この処理系(実行系)は、Prologとしては非常に素朴で、全然、性能は良くありません。(と言うより、むしろ悪い)
この実行系は、テール・リカーシブ・インタープリタになっていません。
開発には、SBCLを使用しました。
以上