自分のためのTips、誰かの為にもなるといいな・・・

Prolog 覚書


SWI-Prolog 組込み関数

SWI-Prologのホーム : http://www.swi-prolog.org/

文字列操作

アトムの連結

連結
?- concat_atom(['A', 'B', 'C'], ' and ', X).

X = 'A and B and C'
分割
?- concat_atom(L, ',', 'a,b,c,d,e').

L = [a, b, c, d, e]

文字コード・アトムの変換

コードからアトム
?- char_code(C,65).

C = 'A'
 アトムからコード
?- char_code('a',N).

N = 97

 文字の種類

アルファベット
?- char_type('A', alpha).

Yes
?- char_type("A", alpha).

Yes
?- char_type(65, alpha).

Yes
?- char_type('1', alpha).

No
2文字以上指定するとエラーになる。以下、種類を調べて(訳して)みました。

種類を表すアトム
一致条件
alpha
アルファベット
alnum アルファベット or 数字
csym
アルファベット or 数字 or アンダースコア(_)
csymf
アルファベット or アンダースコア(_)
ascii
アスキー文字(0-127)
white
スペース or タブ
digit
数字
digit(N)
数字のN
xdigit(N)
Nの16進表記
lower
小文字
lower(Upper)
Upperを小文字にしたもの、Upperは大文字
to_lower(Upper)
Upperを小文字にしたもの、Upperは大文字でも小文字でもよい
upper(Lower)
Lowerを大文字にしたもの、Lowerは小文字
to_upper(Lower)
Lowerを大文字にしたもの、Lowerは大文字でも小文字でもよい
space
レイアウト文字(タブ、Vタブ、改行、など)
end_of_file
-1
end_of_line
行の終わり ASCII:10..13
newline
改行文字(10)
period
ピリオド(「!」、「.」、「?」)
quote
クォーテーション(ダブル「"」、シングル「'」、バック「`」) 
paren(Close)
閉じ括弧 Close に対応する開き括弧(「(」、「[」、「{」)

まず、注意すべきことは、アルファベットは[A-Za-z]でない事。ウムラウトつきの文字やら何やら出てくる。次のようにして調べてみるとよい。(環境によって違うかもしれないが、alnum, csym, csymf, lower, upperも)
:- findall(X, char_type(X, alpha), L), write(L).
確実に[A-Za-z]とするなら次のようにすればよい。
alpha_ascii(X) :- char_type(X, alpha), char_type(X, ascii).
その他、digit, xdigit は数値と文字との変換に使える。

 リスト操作

2つのリストを連結

連結
?- append([1,2,3],[4,5,6],X).

X = [1, 2, 3, 4, 5, 6]
後ろ部分を得る
?- append([1,2,3],X,[1,2,3,4,5]).

X = [4, 5]
前部分を得る
?- append(X,[3,4,5],[1,2,3,4,5]).

X = [1, 2]

リスト要素を選択

選択
?- select(X,[1,2,3],Y).

X = 1,
Y = [2, 3] ;

X = 2,
Y = [1, 3] ;

X = 3,
Y = [1, 2] ;

No
任意の場所への挿入として使える
?- select(4,X,[1,2,3]).

X = [4, 1, 2, 3] ;

X = [1, 4, 2, 3] ;

X = [1, 2, 4, 3] ;

X = [1, 2, 3, 4] ;

No
memberと同じ使い方
?- select(4,[1,2,3,4],_).

Yes

リスト反転

?- reverse(X,[1,2,3]).

X = [3, 2, 1]

最後の要素

?- last([1,2,3],X).

X = 3
 ついでに,最初の要素をとる場合
? - [1,2,3] = [X|_].

一致する要素を削除

?- delete([1,3,2,3],3,X).

X = [1, 2]
応用例:
全て同じ要素からなるか判定
?- delete([1,1,1,1,1],_,[]).

Yes
?- delete([1,1,1,2,1],_,[]).

No

重複なしリスト

重複なしリスト = 集合(set)
?- list_to_set([4,5,6,1,2,3,1,2,3,4,5,6], L).

L = [4, 5, 6, 1, 2, 3]
順序付きの集合(ord_set)
?- list_to_ord_set([4,5,6,1,2,3,1,2,3,4,5,6], L).

L = [1, 2, 3, 4, 5, 6] 

入出力

書式付出力

C言語のprintfのようなもの.エスケープは,バックスラッシュでなくチルダ.
タブの文字数を '~t~10|' のように決めれる,さらに,*で動的に決定できる.
format('~t~*|Hello, World!~n', [4]).
出力
    Hello, World!
 

繰り返しとか

for文のようなことをする
between(1, N, X), write(X), X is N.
文の最後に,XがNになるまでバックトラックで繰り返される.
繰り返しの値で,リストを作成
?- findall(X, between(1, 9, X), L).

L = [1, 2, 3, 4, 5, 6, 7, 8, 9]
これは,次のコマンドと同じ.
?- numlist(1, 9, L).

L = [1, 2, 3, 4, 5, 6, 7, 8, 9]
リストの各項目に演算を施す.
?- maplist(plus(5), [1, 2, 3], L).

L = [6, 7, 8]
この時, plus/3を使用し,plus(5, [1, 2,3]の要素,Lの要素)が呼ばれる.
リストの項目を1つ1行に表示
?- maplist(writeln, [1, 2, 3, 4, 5]).
1
2
3
4
5

findallは、見つかったもののリストを生成するが、繰り返しのたびに行動を起こす場合 forall が使える
?- forall(between(1, 5, X), writeln(X)).
1
2
3
4
5

さらに条件部を括弧で括って次のように出来る。
?- forall((between(1, 10, X), X mod 3 =:= 0), writeln(X)).
3
6
9

その他

式の評価

SWI-Prologで,いわゆるeval関数のような事をしたい場合.term_to_atom/2 が使える.
?- term_to_atom(T,'1+2+3'), X is T.

T = 1+2+3,
X = 6
もちろん,関数でもよい.
?- term_to_atom(T,'writeln(\'Hello, World!\')'), T.
Hello, World!

T = writeln('Hello, World!')

数学関数の定義

例えば,prologでは,y = f(x) = x^2 + x + 1 を以下のように定義できる.
f(X, Y) :- Y is X**2 + X + 1.
次に,このf(x)を使った関数 y = g(x) = f(f(x) + 10) + 10 を定義したい場合,以下のようになる.
g(X, Y) :- f(X, FX), FX1 is FX + 10, f(FX1, Y1), Y is Y1 + 10.
これは,非常に面倒!ここで,以下のコードを追加.
:- arithmetic_function(f/1).
先ほどの関数 f が数学関数として登録される.すると,最後の引数が戻り値となり,
以下のように直感的な書き方ができる.
g(X, Y) :- Y is f(f(X) + 10) + 10.
例:中央値を求める関数
mean(X, Y, Z) :- Z is (X + Y) / 2.
:- arithmetic_function(mean/2).







最終更新 2008/01/30 01:26:12 - yohei
(2007/09/23 02:13:52 作成)


検索

最近気になる言葉
LINQ
atコマンド
最近更新したページ
2015/7/16
2008/9/15
2008/1/30
2007/12/14
2007/11/14
2007/10/25
2007/9/23
2007/5/30