2009年7月7日火曜日

【LPN】8 More Definete Clause Grammars


* 8 More Definete Clause Grammars
- defineteということはindefineteもあるのかどうか、
というのが気になる。
** 1 Extra Arguments
- Context free grammars with features
- 代名詞の導入。
s --> np_subject,vp.

np_subject --> det,n.
np_object --> det,n.
np_subject --> pro_subject.
np_object --> pro_object.

vp --> v,np_object.
vp --> v.

det --> [the].
det --> [a].

n --> [woman].
n --> [man].

v --> [shoots].

pro_subject --> [he].
pro_subject --> [she].
pro_object --> [him].
pro_object --> [her].

- lexicon : 辞書
- 代名詞をいれただけで、これだけ文法を書きかえな
ければいけないのはうまくない。また、代名詞と名
詞は多くの性質を共有しているのにそれをまったく
別に定義する、というのもうまくない。
- これらをうまくやるのがextra arguments。

s --> np(subject),vp.

np(_) --> det,n.
np(X) --> pro(X).

vp --> v,np(object).
vp --> v.

det --> [the].
det --> [a].

n --> [woman].
n --> [man].

v --> [shoots].

pro(subject) --> [he].
pro(subject) --> [she].
pro(object) --> [him].
pro(object) --> [her].

- npにfeaturesを追加した。
- DCG with argumentsは、言語処理のための最新のツー
ルではない。しかし単なるおもちゃでもない。相当に
洗練された文法を記述できる。

- Building parse tree
- うーん、

s(np(det(a),n(woman)),vp(v(shoots))).

(s (np (det a) (n woman)) (vp (v shoots)))

S式の方が見易いと思うんだけどなぁ。まあそれは
PAIPで。

- extra argumentsを利用してparserにする。

s(s(NP,VP)) --> np(NP),vp(VP).

np(np(DET,N)) --> det(DET),n(N).

vp(vp(V,NP)) --> v(V),np(NP).
vp(vp(V)) --> v(V).

det(det(the)) --> [the].
det(det(a)) --> [a].

n(n(woman)) --> [woman].
n(n(man)) --> [man].

v(v(shoots)) --> [shoots].

- DRYではないが、書けるぞ、という感じ。
- extra argsは、semantic representationsを構築す
るのにも便利につかえる。
- semantic representationsはformal languagesによっ
て記述される。例えば、
- first order logic
- discourse representation structures
: 談話言語表示理論
- a database query language
- これらはcompositonaryに構築される。
- というのは単純にそれぞれの単語の意味を結合する
だけではなくて、parse treeの構造をみつつ、意味
を構築していく。

- Beyond context free language
- DCGはCFG以外の文法も記述できる。
- 例えば、{a^nb^nc^n\{e}}。

s(Count) --> ablock(Count),bblock(Count),cblock(Count).
ablock(0) --> [].
ablock(succ(Count)) --> [a],ablock(Count).
bblock(0) --> [].
bblock(succ(Count)) --> [b],bblock(Count).
cblock(0) --> [].
cblock(succ(Count)) --> [c],cblock(Count).

** 2 Extra Goals
- DCGの右側ではPrologの機能を使える。
- それはextra goalsとして、であり、{}で囲む。

s --> ablock(Count),bblock(Count),cblock(Count).
ablock(0) --> [].
ablock(NewCount) --> [a],ablock(Count),
{NewCount is Count + 1}.
bblock(0) --> [].
bblock(NewCount) --> [b],bblock(Count),
{NewCount is Count + 1}.
cblock(0) --> [].
cblock(NewCount) --> [c],cblock(Count),
{NewCount is Count + 1}.
- なお、これはrecogniserとしてのみ使える。

- Separating rules and lexicon
- Extra Goalsの有用な応用として文法と辞書の分離が
ある。
- 自然言語のlexiconsは巨大になるので実戦においても
メリットがある。
- Prologはfirst argment indexingを実施しているの
で、効率もよくなる。
** 3 Concluding Remarks
- DCGはturing-complete。
- "all top-down parsers loop on left-recursive
grammars." なるほど。
- なお、DCGという記法に何か問題があるわけではない。
それのPrologの解釈(実行する手続き)に注意が必要
だということだ。syntaxとsemanticsの分離というこ
とか。
** 4 Exercise
- Exercise 8.1.

s --> np(X),vp(X).

np(X) --> det(X),n(X).
vp(X) --> v(X),np(_).
vp(X) --> v(X).

det(plur) --> [the].
det(sing) --> [the].
det(sing) --> [a].

n(sing) --> [woman].
n(sing) --> [man].
n(sing) --> [apple].
n(sing) --> [pear].
v(plur) --> [eat].

n(plur) --> [women].
n(plur) --> [men].
n(plur) --> [apples].
n(plur) --> [pears].
v(sing) --> [eats].

- Exercise 8.2.

kanga(V,R,Q,A,C) :-
roo(V,R,A,B),
jumps(Q,Q,B,C),
marsupiral(V,R,Q).

** 5 Practical Session

- 1.

lex(woman,n,sing).
lex(man,n,sing).
lex(apple,n,sing).
lex(pear,n,sing).
lex(women,n,plur).
lex(men,n,plur).
lex(apples,n,plur).
lex(pears,n,plur).

lex(a,det,sing).
lex(the,det,sing).
lex(the,det,plur).

lex(eat,v,plur).
lex(eats,v,sing).

lex(he,pro,sing,subj).
lex(she,pro,sing,subj).
lex(him,pro,sing,obj).
lex(her,pro,sing,obj).


s(s(NP,VP)) --> np(NP,X,subj),vp(VP,X).

np(np(DET,N),X,_) --> det(DET,X),n(N,X).
np(np(PRO),X,Y) --> pro(PRO,X,Y).
vp(vp(V,NP),X) --> v(V,X),np(NP,X,obj).
vp(vp(V),X) --> v(V,X).

det(det(Word),X) --> [Word],{lex(Word,det,X)}.
n(n(Word),X) --> [Word],{lex(Word,n,X)}.
v(v(Word),X) --> [Word],{lex(Word,v,X)}.
pro(pro(Word),X,Y) --> [Word],{lex(Word,pro,X,Y)}.

- 2.
/* lexicon */
lex(woman,n,sing,third).
lex(women,n,plur,third).
lex(man,n,sing,third).
lex(men,n,plur,third).
lex(apple,n,sing,third).
lex(apples,n,plur,third).
lex(pear,n,sing,third).
lex(pears,n,plur,third).

lex(a,det,sing).
lex(the,det,sing).
lex(the,det,plur).

lex(eat,v,plur,third).
lex(eats,v,sing,third).
lex(eat,v,plur,first).
lex(eat,v,sing,first).
lex(eat,v,plur,second).
lex(eat,v,sing,second).

lex(i,pro,sing,subj,first).
lex(me,pro,sing,obj,first).
lex(you,pro,sing,subj,second).
lex(you,pro,sing,obj,second).
lex(he,pro,sing,subj,third).
lex(him,pro,sing,obj,third).
lex(she,pro,sing,subj,third).
lex(her,pro,sing,obj,third).

lex(in,prep).
lex(on,prep).
lex(under,prep).
lex(over,prep).

lex(small,adj).
lex(big,adj).
lex(beautiful,adj).
lex(frightened,adj).
lex(fat,adj).
lex(tall,adj).

s(s(GNP,VP)) --> gnp(GNP,SP,subj,Person),vp(VP,SP,Person).

/* general noun phrases */
gnp(gnp(PRO),SP,SO,Person) --> pro(PRO,SP,SO,Person).
gnp(gnp(NP),SP,_,Person) --> np(NP,SP,_,Person).

/* noun phrases */
np(np(DET,NC),SP,_,Person) --> det(DET,SP),nc(NC,SP,Person).
np(np(NP,PP),SP,SO,Person) --> np(NP,SP,SO,Person),pp(PP).

/* noun cores */
nc(nc(N),SP,Person) --> n(N,SP,Person).
nc(nc(ADJ,NC),SP,Person) --> adj(ADJ), nc(NC,SP,Person).

/* preposition phrase */
pp(pp(PREP,GNP)) --> prep(PREP), gnp(GNP,_,obj,_).

/* verb phrases */
vp(vp(V),SP,Person) --> v(V,SP,Person).
vp(vp(V,GNP),SP,Person) --> v(V,SP,Person),gnp(GNP,SP,obj,_).

/* load lexicon */
det(det(Word),SP) --> [Word],{lex(Word,det,SP)}.
n(n(Word),SP,Person) --> [Word],{lex(Word,n,SP,Person)}.
v(v(Word),SP,Person) --> [Word],{lex(Word,v,SP,Person)}.
pro(pro(Word),SP,SO,Person) --> [Word],{lex(Word,pro,SP,SO,Person)}.
prep(prep(Word)) --> [Word],{lex(Word,prep)}.
adj(adj(Word)) --> [Word],{lex(Word,adj)}.


えっと、、、、
形容詞を問題文のように入れると無限ループが発
生するので、いろいろ支障があると思うのだが。形容
詞は2個までとか制限をつけるのかなぁ


最後の課題が結構タフだった。
こつこつ。

【LPN】7 Definite Clause Grammars


* 7 Definite Clause Grammars
** 1 Context Free Grammars
- Prologは多様な目的に利用できるが、発明時の目的と
してcomputational linguistics (計算言語学?、計
算機言語学?)があった。
- Prologにはcomputational linguisticsに有効なツー
ルがたくさんある。
- その筆頭がDCGである。
- DCGは文法を記述するための記法である。
- そもそも文法って何だ。CFGをもってそれを考える。
- CFGの説明。
- CFGはシプサでやったので、用語だけ確認しておく。
- non-terminal symbols
- terminal symbols
- context free rules
- -> : can consist of, can be built out of.
- parse tree : parseは品詞を記述する、構成要素に
分析するという意味らしい。websterだと、Analyze
syntactically by assingning a constituent
structure to (a sentence).
- licensed : "every part of the tree is licesed
by one of our rules", 認可された
- strings : ここではstring of wordsというように
wordの並びをstringという。
- structure : parse treeのもつ構造のこと。
- grammatical : the stringが(given grammarにおい
て)grammaticalであるとは、その文法規則によって
parse treeを構成できることを言う。
- language generated by a grammar : その文法要素
によって生成可能な全てのstringsの総体をこのよ
うに呼ぶ。
- recogniser : stringsがgiven grammarにて生成可
能かどうか判定するプログラム。
- parser : recogniserの機能に加えて、the
structureを示すもの。具体的にはparse treeを示
すもの。
- context free language : context free grammarで
文法を記述可能な言語達のこと。英語はCFGと考え
られている。ドイツ語はCFGでは無いことが証明さ
れている。

- まず、CFGのrecognizerをPrologでどう作るか。
- stringsはlistsとする。
- 対象CFG。

s -> np vp
np -> det n
vp -> v np
vp -> v
det -> 'a
det -> 'the
n -> 'woman
n -> 'man
v -> 'shoots

(注)italic表示のかわりに'を頭につけている。
terminalたちです。

- appendを使う素朴なやり方。
- その1。

s(Z) :- np(X), vp(Y), append(X,Y,Z).
np(Z) :- det(X), n(Y), append(X,Y,Z).
vp(Z) :- v(X), np(Y), append(X,Y,Z).
vp(Z) :- v(Z).
det([the]).
det([a]).
n([woman]).
n([man]).
v([shoots]).

- 動く。しかし、入力情報を探索のガイドにつかって
いないので非効率的。

- その2。
- goalsの順番を変えてみる。

s(Z) :- append(X,Y,Z), np(X), vp(Y).
np(Z) :- append(X,Y,Z), det(X), n(Y).
vp(Z) :- append(X,Y,Z), v(X), np(Y).
vp(Z) :- v(Z).
det([the]).
det([a]).
n([woman]).
n([man]).
v([shoots]).

- 動く。しかしappendとinstansiationsの組み合わせ
は非効率的。traceをみる。

[trace] ?- np([a,woman]).
Call: (7) np([a, woman]) ?
Call: (8) append(_L179, _L180, [a, woman]) ?
Exit: (8) append([], [a, woman], [a, woman]) ?
Call: (8) det([]) ?
Fail: (8) det([]) ?
Redo: (8) append(_L179, _L180, [a, woman]) ?
Call: (9) append(_G366, _L180, [woman]) ?
Exit: (9) append([], [woman], [woman]) ?
Exit: (8) append([a], [woman], [a, woman]) ?
Call: (8) det([a]) ?
Exit: (8) det([a]) ?
Call: (8) n([woman]) ?
Exit: (8) n([woman]) ?
Exit: (7) np([a, woman]) ?
true

- もっとうまい方法はないか。
- ある。
- difference listsという方法。(差分リストとでも言
うのかなぁ)

- difference listsは、2つのリストの差によって対象
となるリストを表現する。

- difference lists版。

s(X,Z) :- np(X,Y), vp(Y,Z).
np(X,Z) :- det(X,Y), n(Y,Z).
vp(X,Z) :- v(X,Y), np(Y,Z).
vp(X,Z) :- v(X,Z).

det([the|W],W).
det([a|W],W).

n([woman|W],W).
n([man|W],W).

v([shoots|W],W).

- これ、昨日flatten書くときに使った手法だ。
- この手法にdifferencial listsという名前をつけて、
汎用化するところが頭いいな。

[trace] ?- s([a,woman,shoots,a,man],[]).
Call: (7) s([a, woman, shoots, a, man], []) ?
Call: (8) np([a, woman, shoots, a, man], _L180) ?
Call: (9) det([a, woman, shoots, a, man], _L198) ?
Exit: (9) det([a, woman, shoots, a, man], [woman, shoots, a, man]) ?
Call: (9) n([woman, shoots, a, man], _L180) ?
Exit: (9) n([woman, shoots, a, man], [shoots, a, man]) ?
Exit: (8) np([a, woman, shoots, a, man], [shoots, a, man]) ?
Call: (8) vp([shoots, a, man], []) ?
Call: (9) v([shoots, a, man], _L234) ?
Exit: (9) v([shoots, a, man], [a, man]) ?
Call: (9) np([a, man], []) ?
Call: (10) det([a, man], _L252) ?
Exit: (10) det([a, man], [man]) ?
Call: (10) n([man], []) ?
Exit: (10) n([man], []) ?
Exit: (9) np([a, man], []) ?
Exit: (8) vp([shoots, a, man], []) ?
Exit: (7) s([a, woman, shoots, a, man], []) ?
true

- うーん。きれい。
- さて、differece listsを使ったrecogniserはかきぶ
りがちょっと汚い。
- そこでDCGの出番。

** 2 Definite Clause Grammars

- DCGは、difference listsを隠蔽してくれるa nice
notation。
- 例。

s --> np,vp.
np --> det,n.
vp --> v,np.
vp --> v.
det --> [the].
det --> [a].

n --> [woman].
n --> [man].

v --> [shoots].

- うむ。構文糖衣というかDSLというか。
- Prologがこれをdifferece listsを使った先の書きぶ
りに変換するとのこと。試す。

?- listing(s).
s(A, C) :-
np(A, B),
vp(B, C).

true.

?-

- ルール追加。

s --> s,conj,s.
conj --> [and].
conj --> [or].
conj --> [but].

- このs,conj,sのsが左再帰問題。
- 語彙を変える。

s --> simple_s.
s --> simple_s,conj,s.
simple_s --> np,vp.
np --> det,n.
vp --> v,np.
vp --> v.
det --> [the].
det --> [a].

n --> [woman].
n --> [man].

v --> [shoots].

conj --> [and].
conj --> [or].
conj --> [but].

- そっか。CFGでnon-terminalについて名前を工夫し
ているときってこういう理由だったんだな。PAIPも
そうやってた。

- formal languageってnatural languageと対を成す
単語なんだ。
- 形式言語(a^n)(b^n)。シプサの世界だ。

s --> [].
s --> l,s,r.

l --> [a].
r --> [b].

** 3 Exercises
- Exercise 7.1.
s(A,D) :-
foo(A,B),bar(B,C),wiggle(C,D).
foo([choo|W],W).
foo(X,Z) :-
foo(X,Y),foo(Y,Z).
bar(X,Z) :-
mar(X,Y),zar(Y,Z).
mar(X,Z) :-
me(X,Y),my(Y,Z).
me([i|W],W).
my([am|W],W).
zar(X,Z) :-
blar(X,Y),car(Y,Z).
blar([a|W],W).
car([train|W],W).
wiggle([toot|W],W).
wiggle(X,Z) :-
wiggle(X,Y),wiggle(Y,Z).

- Exercise 7.2.
s --> l,r.
s --> l,s,r.

l --> [a].
r --> [b].

- Exercise 7.3.
s --> [].
s --> l,s,r,r.

l --> [a].
r --> [b].

** 4 Practical Session
- 1.
s --> [].
s --> w,s,w.
w --> [a].

- 2.
s --> core.
s --> a,s,d.
core --> [].
core --> b,b,core,c,c.
a --> [a].
b --> [b].
c --> [c].
d --> [d].

- 3.
- propositional logic : 命題論理

prop --> [p].
prop --> [q].
prop --> [r].
prop --> not, prop.
prop --> lparen, prop, or, prop, rparen.
prop --> lparen, prop, and, prop, rparen.
prop --> lparen, prop, imp, prop, rparen.

not --> [not].
or --> [or].
and --> [and].
lparen --> ['('].
rparen --> [')'].
imp --> [implies].


この章おもしろかった。
こつこつ。

プログラミングの習作という考え方

プログラミングの学習の道程は長いですね。
まだまだ知識が足りなくて、まともなプログラムが組めるとは思えません。

雛鳥がある日飛び立つように、いろいろな準備がととのったら自然と自分自身のプログラムを書き初めるのかなぁ、と思っています。

もともと書きたいもの、実現したいことはいろいろあるんです。それを実現するために言語としてはCommon Lispを選択しました。その選定だけで1年くらいつかったかもしれません。で、ちゃんとした学習をはじめて1年半くらい。1年半前とくらべれば、自身としては進歩していると思うのですが、知らなければいけないことの分量からすると道遥です。

そのことはこんな風に考えています。

たとえば、理論物理学で何か仕事をなそうと思ったら、やはり大学レベルの物理と数学の理解は仕事の分野によらず大事だと思うのです。ぱっと思いつくところを列記すると(物理だけ)、古典力学、光学、熱力学、解析力学、電磁気学、場の理論、量子力学、特殊相対性理論、一般相対性理論、固体物理、流体力学、統計力学、場の量子論、量子電磁力学、量子色力学、非線形の基礎あたりまでは進む分野にかかわらずきっちりおさえておかないとお話にならないと思うのです。この年齢まで計算機とその周辺というのをじっくりと勉強したことがなかったので、今はそういう蓄積をしているときだという位置付けです。

そんなこんな、なんですが、目標としている成果物じゃなくても、プログラミングにも習作というのがあるのではないか、と思えてきました。もちろん、あるとは思うのですが、自分自身がそれがあると考えられるようになったことが大事です。

Shibuya.lisp TT#3のShiroさんのお話にあったToyであっても、習作としていくつか取り組んでいくこともありなんじゃないかと思えてきました。

それは模写かもしれないしスケッチかもしれないし、そういうメタファのない何かかもしれません。

ちょっと考えてみようと思います。

2009年7月6日月曜日

【LPN】6 More Lists


* 6 More Lists
** 1 Append
- unificationは構造の構築にも使える。
- そしてunificationで構造の構築を記述すると、構造
の分解にも同じ述語を使える。これがすごい。

append([],L,L).
append([H|T],L2,[H|L3]) :-
append(T,L2,L3).

?- append([a,b],[1,2],X).
X = [a, b, 1, 2].

?- append(X,Y,[a,b,1,2]).
X = [],
Y = [a, b, 1, 2] ;
X = [a],
Y = [b, 1, 2] ;
X = [a, b],
Y = [1, 2] ;
X = [a, b, 1],
Y = [2] ;
X = [a, b, 1, 2],
Y = [] ;
fail.

?-

** 2 Reversing a List
- Exercise 6.1.

doubled(L) :- append(X,X,L).

やっぱ頓知かな。

- Exercise 6.2.

parindrome(L) :- rev(L,X), L = X.

これは簡単。

- Exercise 6.3.

toptail(I,[H,T]) :- append([H|_],[T],I).

あ、仕様を読み間違えている。これはtopとtailから
なるlistをつくる。正しくは、topとtail以外のlist
をつくるのだから、、、、

toptail([_|T],O) :- append(O,[_],T).

頓知。

具体的な入出力例をいろいろ書き下していみるのは、
宣言的プログラミングでも効果的。

- Exercise 6.4.

lastRev(List,X) :- rev(List,[H|_]), H = X.

lastRec([Y],X) :- Y = X.
lastRec([_|T],X) :- lastRec(T,X).

- Exercise 6.5.

swapfl([H1|T1],[H2|T2]) :-
append(X,[H1],T2),
append(X,[H2],T1).

backtrackするとappendがとまらないが。

swapflRec([A,B],[B,A]).
swapflRec([H1,C|T1],[H2,C|T2]) :-
swapflRec([H1|T1],[H2|T2]).

再帰は友達。

- Exercise 6.6.


** Practical Session

- 1.

amember(X,L) :- append(_,[X|_],L).

非効率的だろう。

- 2.

まず、こう書いた。

set(_,[]).
set(L,[H|T]) :- member(H,L), set(L,T).

これは述語としては機能するが、構築には使えない。
構築につかえる書きぶりはより宣言的でなければなら
ない。

set(L,S) :- setBuf(L,[],S).
setBuf([H|T],B,S) :-
member(H,B), setBuf(T,B,S);
setBuf(T,[H|B],S).
setBuf([],B,B).

こちらは、構築にもつかえるが集合の要素の順番が異
なるときの判定には対応していない。まあいいや。


- 3.

うーん。Common Lispならすぐ書ける。

(defun flatten (tree)
(cond ((null tree) nil)
((atom (car tree)) (cons (car tree)
(flatten (cdr tree))))
(t (append (flatten (car tree))
(flatten (cdr tree))))))

PrologのProof Searchで解がでるように宣言を考える
ことにはどういう意味があるんだろう。もしそれに意
味が無いならば、それはPrologのために考えているだ
けであり、無意味になってしまうところがこわい。

Prologが探索型開発に向かないのは、問題の分割がや
りにくいからかな。

自分において、その理由を考えてみるとHtDPのデザイ
ンレシピが適用できないことがある。

論理プログラミングのデザインレシピってつくれない
のだろうか。。。

とりあえず、flatten。

flatten([],[]). /* トリビアルなケース。これ以降ちゃんとしたリストであることが保証される */
flatten([X],F) :- flatten(X,F). /* 余分な全体括弧を除去 */
flatten([[H]|T],F) :- flatten([H|T],F). /* headの余分な括弧を除去 */
flatten([[LHH|LHT]|T],[FH|FT]) :- /* headが(意味のある)リストの場合 */
flatten([LHH|LHT],[FH|XT]),flatten([XT|T],FT).
flatten([FH|LT],[FH|FT]) :- flatten(LT,FT). /* headがリストではない場合 */

こつとしては、はじめはrulesのheadはシンプルにし
てbodyのunificationで分解していく。代入がごとく。
そして動くものができたところで、unificationをま
とめていき不要なvariablesを消す。こうすると多少
探索的に書いていける。

ただし、宣言的プログラミングはその正しさが判別し
やすい、というが、上のflattenはとてもそうは思えな
い。こういうケースもあるのか、私のflattenがいけ
てないのか。


こんなもんでPons Asinorumを渡れたのかなぁ。。。

ふー。やっと折り返し地点。いくら初めての言語とはい
え、まったくの入門書なんだからもっとスピーディにい
かんもんかなぁ。頭がポンコツすぎる。

たかがポンコツ、されどポンコツ。

【LPN】5 Arithmetic


* 5 Arithmetic
** 1 Arithmetic in Prolog
- この本では整数しかやらないよ。
- こんな感じ。
?- 8 is 6+2.
true.

?- 8 is 6 + 2.
true.

?- is(8,+(6,2)).
true.

?- X is 6+2.
X = 8.

?-
- (is 8 (+ 6 2))でもよかったじゃん、と思う。まあ
それはPAIPで、ということで。

** 2 A Closer Look
- +-*/などは単なるfunctorである。
?- X = 3+2.
X = 3+2.

?-
これは単なるUnification。それは=/2が統制してい
る。
- 計算を統さどるのはis。
- isは逆演算はできない点に注意。

?- X is 6+2.
X = 8.

?- 6+2 is X.
ERROR: is/2: Arguments are not sufficiently instantiated

?- X = 2, Y is X*3.
X = 2,
Y = 6.

?- Y = 6, Y is X*3.
ERROR: is/2: Arguments are not sufficiently instantiated
?-

** 3 Arithmetic and Lists
- len/2の実装。
- accumulaterの導入。accLen/3、leng/2。
- 末尾再帰の効用の紹介。

** 4 Comparing Integers
- =:= Common Lispの=みたいなもの。
- =\= Common Lispの\=みたいなもの。
- 比較演算子はinstantiationsを実施しない。
?- X < 3.
ERROR: ?-
- あ、なるほど。制御構造のPrologでの表現はこんな
感じ。

accMax([H|T],A,Max) :-
H > A, accMax(T,H,Max);
H =< A, accMax(T,A,Max).
accMax([],A,A).

** 5 Exercise
- Exercise 5.1.
- 1. X = 3*4.
X = 3*4.
- 2. X is 3*4.
X = 12.
- 3. 4 is X.
ERROR.
- 4. X = Y.
X = Y.
- 5. 3 is 1+2.
true.
- 6. 3 is +(1,2).
true.
- 7. 3 is X+2.
ERROR.
- 8. X is 1+2.
X = 3.
- 9. 1+2 is 1+2.
true.
おお、間違えた。これfail。
isの左引数はis的評価をしないのか。
- 10. is(X,+(1,2)).
X = 3.
- 11. 3+2 = +(3,2).
true.
- 12. *(7,5) = 7*5.
true.
- 13. *(7,+(3,2)) = 7*(3+2).
true.
- 14. *(7,(3+2)) = 7*(3+2).
true.
- 15. 7*3+2 = *(7,+(3,2)).
fail.
- 16. *(7,(3+2)) = 7*(+(3,2)).
true.

- Exercise 5.2.
increment(M,N) :- N is M + 1.
sum(M,N,Sum) :- Sum is M + N.

- Exercise 5.3.
addone([],[]).
addone([H1|T1],[H2|T2]) :-
H2 is H1 + 1, addone(T1,T2).

- 油断するとすぐに手続きから考えてしまう。成立す
べき様子というか条件を考えて素直にそれを記述す
べし。

** 6 Practical Session
- 1
accMin([H|T],A,Min) :-
H < A, accMin(T,H,Min);
H >= A, accMin(T,A,Min).
accMin([],A,A).

- 2

scalarMult(_,[],[]).
scalarMult(N,[LH|LT],[RH|RT]) :-
RH is N * LH, scalarMult(N,LT,RT).

- 3

dot([],[],0).
dot([Ha|Ta],[Hb|Tb],A) :-
Anew is A + Ha * Hb, dot(Ta,Tb,Anew).

だとうまくいかない。accumulatorを使うとうまくいく。

dot_acc([],[],A,A).
dot_acc([Ha|Ta],[Hb|Tb],A,R) :-
Anew is A + Ha * Hb, dot_acc(Ta,Tb,Anew,R).
dot(Va,Vb,Result) :-
dot_acc(Va,Vb,0,Result).

なぜかというと、accumulatorをつかうとisの右引数のA
が具体的な数値になるから。


Lisp -> Lisper
Ruby -> Rubyist
Python -> Pythonista
Prolog -> Prologger?, Prologician? ???

こつこつ。

2009年7月5日日曜日

【LPN】4 Lists

リストになると俄然元気になる。

* 4 Lists
** 1 Lists
- リストだ!
- |はa special built-in operator。listsを分解する。
- |はUnificationとともに使える。
- variablesはunificationにてlistsもinstantiateで
きる。
- []はa special list。|で分解できない。
- 全てのlistsは、|の観点でいうと、[]で終端されてい
る。
- the anonymous variableは埋め草。
- そのbindingsは全て個別。
** 2 Member
- termsじゃなくてobjectsと言う表現がここで出始めて
いる。ここまでで言うと、terms + lists = objects
ということかな?
** 3 Recursing down Lists
- 入力にvariablesが使えるところがPrologの際立つと
ころ。
** 4 Exercise
- Exercise 4.1.
- 1. [a,b,c,d] = [a,[b,c,d]].
fail.
- 2. [a,b,c,d] = [a|[b,c,d]].
true.
- 3. [a,b,c,d] = [a,b,[c,d]].
fail.
- 4. [a,b,c,d] = [a,b|[c,d]].
true.
- 5. [a,b,c,d] = [a,b,c,[d]].
true.
- 6. [a,b,c,d] = [a,b,c|[d]].
true.
- 7. [a,b,c,d] = [a,b,c,d,[]].
fail.
- 8. [a,b,c,d] = [a,b,c,d|[]].
true.
- 9. [] = _.
true.
- 10. [] = [_].
fail.
- 11. [] = [_|[]].
fail.
- Exercise 4.2.
- 1. [1|[2,3,4]]
correct. 4 elements.
- 2. [1,2,3|[]]
correct. 3 elements.
- 3. [1|2,3,4]
incorrect.
- 4. [1|[2|[3|[4]]]]
correct. 4 elements.
- 5. [1,2,3,4|[]]
correct. 4 elements.
- 6. [[]|[]]
correct. 1 elements.
- 7. [[1,2]|4]
incorrect.
- 8. [[1,2],[3,4]|[5,6,7]]
correct. 5 elements.
- Exercise 4.3.
second(X,[_,X|_]).

すごくコンパクトな述語定義だ。Prologのパワー。

- Exercise 4.4.
swap12([X,Y|T],[Y,X|T]).

うーん。気持ちいい。

- Exercise 4.5.
listtran([],[]).
listtran([G|GT],[E|ET]) :-
tran(G,E),
listtran(GT,ET).

慣れてきた。
- Exercise 4.6.
twice([],[]).
twice([X|T1],[X,X|T2]) :- twice(T1,T2).

- Exercise 4.7.
割愛。
** 5 Practical Session

combine1([],[],[]).
combine1([H1|T1],[H2|T2],[H1,H2|T3]) :-
combine1(T1,T2,T3).

combine2([],[],[]).
combine2([H1|T1],[H2|T2],[[H1,H2]|T3]) :-
combine2(T1,T2,T3).

combine3([],[],[]).
combine3([H1|T1],[H2|T2],[j(H1,H2)|T3]) :-
combine3(T1,T2,T3).

こつこつ。

【LPN】3 Recursion


* 3 Recursion
** 1 Recursive Definitions
- stork: コウノトリ
- "Let's now consider both the declarative and
procedual meanings of the definition" ! 両方の
意味があるのか!
- 宣言的な意味は、PrologのKBの内容を論理的な言明
群と考えたとおりの字句通りのこと。
- 手続き的な意味は、そのKBに具体的なクエリをしたと
きの、具体的にPrologが実施するproof search処理の
こと。
- descendant: 子孫、末裔
** 2 Rule Ordering, Goal Ordering, and Termination
- Prologは、論理プログラミング言語として、完全で
はない。ここで完全ではない、というのは、宣言的
な記述をするだけであとは計算機がやってくれると
いうことができないということ。
- Prologでは、手続き的な側面も大事である。それは、
KBを上から下に探索するということ、サブゴールを
左から右に探索するということ、探索が失敗したと
きに直前の選択ポイントにバックトラックするとい
うこと。
- goalsの順番は重要。探索が止まらなくなる。
- left recursive rule: 左再帰ルール?
- headのfunctorはbodyではできるだけ遠くへ置け。
- 実践的に言うと、まず論理プログラミングの精神に
て問題を宣言的に記述する。それが終わったら、
Prologの手続き的観点からそれをチューンナップせ
よ。
** 3 Exercise
- Exercise 3.1.

descend(X,Y) :- child(X,Y).
descend(X,Y) :- descend(X,Z), descend(Z,Y).

まず、これは宣言的には正しそうだ。しかし手続き
的には止まらなくなりそうだ。止まらないケースを
シミュレーションしてみる。

descend(a,b).というクエリに対して、

まず、

descend(X,Y) :- child(X,Y).

に失敗するとする。すると、

descend(X,Y) :- descend(X,Z), descend(Z,Y).

を適用するので、サブゴールは、

descend(a,_G1), descend(_G1,b).

となる。左からやるのがルールなので、
descend(a,_G1)を探すが、

descend(X,Y) :- child(X,Y).

は失敗するとする。すると、

descend(a,_G2), descend(_G2,_G1).

の探索になり、これは終了しない探索になる。

- Exercise 3.2.

directlyIn(natasha,irina).
directlyIn(olga,natasha).
directlyIn(katarina,olga).
in(X,Y) :- directlyIn(X,Y).
in(X,Y) :- directlyIn(X,Z), in(Z,Y).

- Exercise 3.3.

travelFromTo(X,Y) :- directTrain(X,Y).
travelFromTo(X,Y) :- directTrain(Y,X).

travelFromTo(X,Y) :- directTrain(X,Z),travelFromTo(Z,Y).

- Exercise 3.4.

greater_than(succ(X),0).
greater_than(succ(X),succ(Y)) :- greater_than(X,Y).

- Exercise 3.5.

swap(leaf(X),leaf(Y)) :- =(X, Y).
swap(tree(LL,LR),tree(RL,RR)) :-
swap(LL,RR),
swap(LR,RL).

- Prologのfunctorを立案するときの頭の使い方はLisp
系言語の関数立案時とは全然違う。
- Lisp系のように再帰が便利とか重要とかいうレベルで
はなく、再帰が無いとプログラムにならない。書けな
い、じゃなくて、ならない。再帰はPrologの核であ
る。ウーン。うまい表現がみあたらない。
** 4 Practical Session
- 論理プログラミングは探検的プログミング手法には
向かないかもしれない。宣言的な記述を考えるのっ
て、何か頓知に近い気がする。慣れの問題なのかなぁ。


PAIPに通じる概念や観点が散見される。やはり古典的AIというのはProlog的なのだろうか。

こつこつ。