カット

バックトラックを禁止する述語らしい。これを使えば リスト - 放牧日記のtakeやdropも

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).

my_nth(1, [Car|_], Car) :- !.
my_nth(N, [_|Cdr], Elem) :-
	N > 1, N1 is N - 1. my_nth(N1, Cdr, Elem).

見たいな無理やりな記述ができる。本来の目的とは異なる気もする。
とりあえず、カットはそこから後戻りができなくなる演算子と覚えておく。
カットを使えばif文や繰り返しが記述できる。

if(Test, Then, _) :- Test, !, Then.
if(_, _, Else) :- Else.

leap(Year) :-
	if(Year mod 400 =:= 0, true,
	   if(Year mod 100 =:= 0,fail,
	      if(Year mod 4 =:= 0, true, fail)
	     )
	  ).

また、ifは->という演算子で記述できる。

leap(Year) :-
	Year mod 400 =:= 0 -> true ;
	Year mod 100 =:= 0 -> fail ;
	Year mod   4 =:= 0 -> true ;
	fail.

明らかに読みやすいし、何かErlangくさい(ほんとは逆だが。

repeatと言うのがバックトラックしてきたのを跳ね返す演算子らしく、繰り返しを記述できる。
他は末尾再帰などで記述するのがよいらしい。

/* 再起 */
fact(N, Acc) :-
	N > 0, N1 is N - 1, fact(N1, Acc1), Acc is N * Acc1.
fact(0, 1).

/* 一応末尾再起? */
fact(N, Acc) :- fact_sub(N, 1, Acc).
fact_sub(N, Acc, Result) :-
	N > 0, N1 is N - 1, Acc1 is Acc * N, fact_sub(N1, Acc1, Result).
fact_sub(0, Acc, Acc).

prologの末尾再帰良く分からん。何か違う気もしてきた。