リスト

prologのリストのリテラル表記。

[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}
| ?-

こっちなら意図したような動作になった。