リスト
[this, is, a, list].
リストはLISPと同じようなセルになっている。
[Car | Cdr]
これはyes。LISPのリストとまったく一緒。
| ?- [a | [b | [c | []]]] = [a, b, c].
take
appendは昨日やったので、takeなどを定義してみた。
my_take(0, _, []). my_take(N, [Lcar | Lcdr], [Lcar | R]) :- N > 0, N1 is N - 1, my_take(N1, Lcdr, R). my_drop(0, L, L). my_drop(N, [_ | Lcdr], R) :- N > 0, N1 is N - 1, my_take(N1, Lcdr, R). my_split_at(0, L, [], L). my_split_at(N, [Lcar | Lcdr], [Lcar | F], R) :- N > 0, N1 is N - 1, my_split_at(N1, Lcdr, F, R).
_は無名変数といって、その部分の変数を使わないときに名前をつける代わりに使う。Erlangはここら辺を引き継いでいるらしい。
この定義ではおかしいらしく、
| ?- my_take(0, [1, 2, 3, 4], R). my_take(0, [1, 2, 3, 4], R). R = [] ? ; ; no | ?- my_take(2, [1, 2, 3, 4], R). my_take(2, [1, 2, 3, 4], R). R = [1,2] ? ; ; no | ?-
のように他の解を探すかどうか質問される。
デバッグ
GNU Prologでtraceという述語でトレースができたので、その結果を。
my_take(0, _, []). my_take(N, [Lcar | Lcdr], [Lcar | R]) :- N > 0, N1 is N - 1, my_take(N1, Lcdr, R).
がプログラムだとして、
| ?- [user]. [user]. compiling user for byte code... my_take(0, _, []). my_take(N, [Lcar | Lcdr], [Lcar | R]) :- N > 0, N1 is N - 1, my_take(N1, Lcdr, R). my_take(0, _, []). my_take(Nmy_take(N, [Lcar | Lcdr], [Lcar | R]) :- N N > 0, N1 is N - 1, my_take(N1, Lcdr, R). user compiled, 4 lines read - 819 bytes written, 10147 ms yes | ?- trace. trace. The debugger will first creep -- showing everything (trace) yes {trace} | ?- my_take(1, [1,2,3], R). my_take(1, [1,2,3], R). 1 1 Call: my_take(1,[1,2,3],_22) ? 2 2 Call: 1>0 ? 2 2 Exit: 1>0 ? 3 2 Call: _122 is 1-1 ? 3 2 Exit: 0 is 1-1 ? 4 2 Call: my_take(0,[2,3],_55) ? 4 2 Exit: my_take(0,[2,3],[]) ? 1 1 Exit: my_take(1,[1,2,3],[1]) ? R = [1] ? ; ; 1 1 Redo: my_take(1,[1,2,3],[1]) ? 4 2 Redo: my_take(0,[2,3],[]) ? 5 3 Call: 0>0 ? 5 3 Fail: 0>0 ? 4 2 Fail: my_take(0,[2,3],_55) ? 1 1 Fail: my_take(1,[1,2,3],_22) ? (4 ms) no {trace} | ?- my_take(0, [1,2,3], R). my_take(0, [1,2,3], R). 1 1 Call: my_take(0,[1,2,3],_22) ? 1 1 Exit: my_take(0,[1,2,3],[]) ? R = [] ? ; ; 1 1 Redo: my_take(0,[1,2,3],[]) ? 2 2 Call: 0>0 ? 2 2 Fail: 0>0 ? 1 1 Fail: my_take(0,[1,2,3],_22) ? no {trace} | ?-
どうやら、ルールの順番がいけないらしい。
順番を変えた時の結果は、
| ?- [user]. [user]. compiling user for byte code... my_take(N, [Lcar | Lcdr], [Lcar | R]) :- N > 0, N1 is N - 1, my_take(N1, Lcdr, R). my_take(0, _, []). my_take(N, [Lcar | Lcdr], [Lcar | R]) :- N N > 0, N1 is N - 1, my_take(N1, Lcdr, R). my_take(0my_take(0, _, []). user compiled, 4 lines read - 819 bytes written, 2045 ms yes | ?- trace. trace. The debugger will first creep -- showing everything (trace) yes {trace} | ?- my_take(1, [1,2,3], R). my_take(1, [1,2,3], R). 1 1 Call: my_take(1,[1,2,3],_22) ? 2 2 Call: 1>0 ? 2 2 Exit: 1>0 ? 3 2 Call: _122 is 1-1 ? 3 2 Exit: 0 is 1-1 ? 4 2 Call: my_take(0,[2,3],_55) ? 5 3 Call: 0>0 ? 5 3 Fail: 0>0 ? 4 2 Exit: my_take(0,[2,3],[]) ? 1 1 Exit: my_take(1,[1,2,3],[1]) ? R = [1] yes {trace} | ?- my_take(0, [1,2,3], R). my_take(0, [1,2,3], R). 1 1 Call: my_take(0,[1,2,3],_22) ? 2 2 Call: 0>0 ? 2 2 Fail: 0>0 ? 1 1 Exit: my_take(0,[1,2,3],[]) ? R = [] yes {trace} | ?-
こっちなら意図したような動作になった。