カット
バックトラックを禁止する述語らしい。これを使えば リスト - 放牧日記の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の末尾再帰良く分からん。何か違う気もしてきた。