htmllist=[]; htmllist.push({"file":"manuals/tool_install.html","title":"【補足資料】VS2013 x86 Cross Tools コマンド プロンプトを使う前に","text":"【補足資料】VS2013 x86 Cross Tools コマンド プロンプトを使う前に,*32ビット版をお使いの場合は、以下の説明中の「VS2013 x64」を「VS2013 x86」に読み換えてください。,デスクトップにショートカットを作成するには,①「スタートメニュー =>全てのプログラム =>Visual Studio 2013 =>Visual Studio ツール =>VS2013 x64 Cross Tools コマンド プロンプト」を右クリックします。,②メニューから「送る(N) =>デスクトップ(ショートカットを作成)」をクリックします。,作業フォルダを書き換えるには,①デスクトップに作成された 「VS2013 x64 Cross Tools コマンド プロンプト」を右クリックします。,②メニューからプロパティを選びます。,③「VS2013 x64 Cross Tools コマンド プロンプトのプロパティ」画面(ショートカットタブ)が開くので、"作業フォルダ"をユーザの作業フォルダに書き換えます。,「7.コンパイラ」へ戻る"}); htmllist.push({"file":"manuals/manual_tfs.html#Section04","title":"組み込み型","text":"組み込み型,一部の型は組み込み型として用意されており、これらは定義しなくとも使うことができます。新たに定義しようとするとエラーになります。,bot, list, string, atom, integer, float,bot 型は、前述のとおり、すべての型の supertype となる型です。list 型、string 型、atom 型、integer 型、 float 型はそれぞれ任意のリスト、文字列、アトム、整数、実数に対応する型です (後で述べるように、素性の値の指定に用いられます) 。"}); htmllist.push({"file":"manuals/manual_tfs.html#Section05","title":"素性","text":"素性,次の書式を用いて、型に任意の項を持たせることができます。,型&項,項が素性構造の場合、素性構造の中の素性とペアとなる値もまた型を持ちますが、これも同様に任意の項を持つことができるため、入れ子構造を作ることができます。これを型付素性構造と呼びます。,素性構造の表記法など、基本的な仕様は型のない素性構造と同じです。ただし、型が持つ素性構造においてはその型で定義された素性以外を使うことはできません。また、素性構造内において、素性とペアになる値に与えることのできる型は、素性の定義の際に指定された型と単一化されるものに限られます。,型付素性構造は次の書式で表されます。,型&{素性1:素性1の値, 素性2:素性2の値, ...},以下に示すのは、入れ子状になった型付素性構造の例です。 ,油彩画&{作品名:星月夜,,作者:人物&{名前:フィンセント・ファン・ゴッホ,,出身地:オランダ&},,制作年:1889,,展示場所:施設&{施設名:ニューヨーク近代美術館,,所在地:ニューヨーク州&}}, これは全体として「油彩画」型の値を持ちます。素性の値に登場する「人物」「施設」「オランダ」「ニューヨーク州」も型となっています。「フィンセント・ファン・ゴッホ」「ニューヨーク近代美術館」はアトムであり、"1889" は整数です。,型付素性構造を使用するためには、 fs_mode/2 述語を用いて、素性構造モードを型付素性構造モードに切り替える必要があります。ただし、型定義を含むファイルをコンサルトした時点で、この切り替えは自動的に行われます。,型付素性構造は、型のない素性構造の場合と同様に、 fs_writeAVM/1 述語を用いて AVM 形式で出力することができます。,<例>,| ?- X = 彫刻&{作品名:ミロのヴィーナス,展示場所:施設&{施設名:ルーヴル美術館,所在地:フランス&}}, fs_writeAVM(X).,|~彫刻 ~|,| 作品名: ミロのヴィーナス |,| 作者: 人物 |,| 制作年: integer |,| 展示場所:|~施設 ~| |,| | 所在地:フランス& | |,| | 施設名:ルーヴル美術館 | |,| |_ _| |,|_ _|,X = 彫刻&{作品名:ミロのヴィーナス,展示場所:施設&{施設名:ルーヴル美術館,所在地:フランス&}}.,yes,型付素性構造が AVM 形式で出力される際には、最初に型についての情報が表示された後、素性とその値が列挙されます。 "}); htmllist.push({"file":"manuals/manual_tfs.html#Section06","title":"素性を持つ型の定義","text":"素性を持つ型の定義,素性を用いるためには、あらかじめ素性を定義しておく必要があります。,素性の定義は、型定義に加えて、素性と素性が持つ型のペアを列挙することで行われます。,型 <- [型1, 型2, ...] + [素性1:素性1の型, 素性2:素性2の型, ...].,素性名として用いることのできる文字列の種類は、アトムに用いることのできるものと同一です。ある型で定義した素性は、それを継承した型でも引き継がれます。素性を定義した型の subtype 以外では同じ素性を用いることはできません。,先ほどの美術品の例のような素性構造を定義するためには、例えば以下のような宣言が必要になります。,場所 <- [bot].,ヨーロッパ <- [場所].,オランダ <- [ヨーロッパ].,フランス <- [ヨーロッパ].,北米 <- [場所].,アメリカ合衆国 <- [北米].,ニューヨーク州 <- [アメリカ合衆国].,人物 <- [bot] + [名前:atom, 出身地:場所].,施設 <- [bot] + [施設名:atom, 所在地:場所].,美術品 <- [bot] + [作品名:atom, 作者:人物, 制作年:integer, 展示場所:施設].,油彩画 <- [美術品].,彫刻 <- [美術品].,素性がとることのできる値は、素性定義の際に指定した型とその subtype に限られます。例えば、素性「出身地」は「場所」型とその subtype だけを値として持つことができます。素性の型に組み込み型を指定した場合、素性がとることのできる値は、組み込み型が定めた値のみに制約されます。例え ば、素性「制作年」が取ることのできる値は整数のみになります。,素性の型を組み込み型の list 型とすることで、複数の値を列挙することができます。,<例>,% 型と素性の定義,s <- [bot].,t <- [bot] + [f:list].,以下では、素性 f の値は数字、アトム、s 型からなるリストとなります。,| ?- X = t&{f:[12345, abcdefgh, s&]}, fs_writeAVM(X).,|~t ~|,| f: [ |,| 12345 |,| ,abcdefgh |,| ,s& |,| ] |,|_ _|,X = t&{f:[12345,abcdefgh,s&]}.,yes,素性は原則として一度しか定義できません。ただし、ある素性を持つ型から継承して、その subtype の定義を行う際に、同じ素性を再定義し、素性が持つ値の制約を強めることは可能です。具体的には、素性の値の型を、当初定義されたものの subtype に更新する記述が可能です。,<例>,animal <- [bot] + [father:animal, mother:animal].,dog <- [animal] + [father:dog, mother:dog].,この場合、animal 型が持つ素性 father と mother は animal 型ですが、これを継承した dog 型が持つ素性 father と mother がとれるのは dog 型のみです。"}); htmllist.push({"file":"manuals/manual_tfs.html#Section07","title":"素性を持つ型の単一化","text":"素性を持つ型の単一化,型付素性構造どうしの単一化においては、まず型の単一化が行われ、それに成功すると続いて対応する素性どうしの単一化が行われます。これを再帰的に繰り返していき、どの単一化も失敗することなく完了すれば、型付素性構造の全体が単一化されたことになります。,<例>,% 型と素性の定義,香辛料 <- [bot].,わさび <- [香辛料].,唐辛子 <- [香辛料].,一味唐辛子 <- [唐辛子].,七味唐辛子 <- [唐辛子].,麺類 <- [bot] + [薬味:香辛料, 価格:integer].,そば <- [麺類].,冷やしそば <- [そば].,きつねそば <- [そば].,月見そば <- [そば].,冷やしきつねそば <- [冷やしそば, きつねそば].,冷やし月見そば <- [冷やしそば, 月見そば].,うどん <- [麺類].,型が単一化でき、素性の値の型も単一化できる場合,| ?- X = 冷やしそば&{薬味:一味唐辛子&}, X = きつねそば&{薬味:唐辛子&}.X = 冷やしきつねそば&{薬味:一味唐辛子&{}}.yes,型が単一化できない場合,| ?- X = 冷やしそば&{薬味:唐辛子&}, X = うどん&{薬味:唐辛子&}.,no,型は単一化できるが、素性の値の型が単一化できない場合,| ?- X = 月見そば&{薬味:七味唐辛子&}, X = そば&{薬味:わさび&}.,no,型が単一化でき、片方には対応する素性が存在しないような場合,| ?- X = きつねそば&{薬味:一味唐辛子&}, X = そば&{価格:700}.,X = きつねそば&{薬味:一味唐辛子&{}, 価格:700}.,yes,一方の型付素性構造が持つ素性とその値が、もう一方の型付素性構造には存在しない場合、存在する側の素性とその値が単一化先に引き継がれます。"}); htmllist.push({"file":"manuals/manual_tfs.html#Section08","title":"型推論","text":"型推論,AZ-Prolog ではコンサルトの際、およびトップレベルからの入力を評価する際に素性構造に対し型推論および型検査を行います (素性構造モードが型付素性構造モードのとき) 。,型のみで素性構造を備えていない場合、空の素性構造が付与されます。型情報が省略された素性構造には、推論により自動的に型が補われます。また、型と素性の対応、および素性と素性値の対応が、定められた制約を満たしているか検査されます。型検査の結果、エラーが生じなければ型推論によって適切な型に変換されます。,以下に、型推論および型検査の具体的な手順を示します。なお、以降の例においては次のような型定義が前もってなされていると仮定しています。,% 型と素性の定義 (型推論のすべての例で共通),職業 <- [bot].,農家 <- [職業] + [作物:atom].,漁師 <- [職業] + [漁船数:integer].,医者 <- [職業] + [診療科:atom].,プログラミング言語 <- [bot].,'C言語' <- [プログラミング言語].,外国語 <- [bot].,英語 <- [外国語].,通訳 <- [職業] + [通訳言語:外国語].,1.型のみが与えられており素性構造が付与されていない場合には、(素性値を持たない) 型付素性構造に変換されます。,<例>,t1 :- X = 職業&, write(X), nl.,(実行結果),| ?- t1.,職業&{},yes,2.型を持たない素性構造の場合、素性を参照し、その素性を定義している型が発見できたら、素性構造にその型を割り当てます。型の候補が複数存在するときは、その中で最も一般的な型を割り当てます。与えられた素性を定義している型が見つからない場合や、素性の組み合わせ方に不整合があり、型が決定できない場合にはエラーとなります。,<例>,推論で型が補われる場合,t2 :- X = {作物:トウモロコシ}, write(X), nl.,(実行結果),| ? - t2.,農家&{作物:トウモロコシ},yes,素性と関連付けられた型が存在しない場合,t3 :- X = {科目:音楽}, write(X), nl. % コンサルト時エラー,素性構造内のすべての素性と関連付けられた型が存在しない場合,t4 :- X = {漁船数:5, 診療科:外科}, write(X), nl. % コンサルト時エラー,3.型を持つ素性構造の場合も、まず素性構造だけを手がかりに型推論を行います。その上で、推論によって得られた型とプログラムに記述された型を単一化し、その結果となる型を割り当てます。単一化に失敗すればエラーとなります。,<例>,与えた型と素性から推論した型に矛盾がない場合,t5 :- X = 漁師&{漁船数:2}, write(X), nl.,(実行結果),| ?- t5.,漁師&{漁船数:2},yes,t6 :- X = 職業&{漁船数:2}, write(X), nl.,(実行結果),| ?- t6.,漁師&{漁船数:2},yes,与えた型と推論した型が単一化できない場合,t7 :- X = 医者&{作物:ブドウ}, write(X), nl. % コンサルト時エラー,4.型が確定したら、次にそれぞれの素性に対して、素性値の型推論を行います。素性定義の際に素性値に与えた型を調べ、これをプログラム中の素性値の型と単一化します。単一化に成功すれば、その結果となる型で素性値を置き換えます (プログラム中の素性値が素性定義で与えた型の subtype ならば値は不変です) 。単一化に失敗すればエラーとなります。素性定義において組み込み型が与えられていた場合は、それに対応する値を素性が持っているかどうか検査します。,<例>,素性値の型と素性値がとりうる型とが矛盾しない場合,t8 :- X = 通訳&{通訳言語:英語&}, write(X), nl.,(実行結果),| ?- t8.,通訳&{通訳言語:英語&{}},yes,素性値の型が素性値がとりうる型ではない場合,t9 :- X = 通訳&{通訳言語:'C言語'&}. % コンサルト時エラー,素性値が組み込み型が指定する種類の値ではない場合,t10 :- X = 漁師&{漁船数:トロール漁船}. % コンサルト時エラー,5.素性構造が入れ子状になっている場合には、上の手順を内側の素性構造に対して再帰的に実行し、すべての型推論および型検査が問題なく完了すれば成功となります。"}); htmllist.push({"file":"manuals/manual_tfs.html#Section09","title":"構造共有","text":"構造共有,以下の例において、p(X) が真となるような X においては、本人の出生地と母親の現在地が必ず等しくなります。同様に、q(X) が真となるような X においては、本人の出生地と本人の現在地が必ず等しくなります。,人 <- [bot] + [出生地:atom, 現在地:atom, 父親:人, 母親:人].,p(人&{出生地:L, 現在地:岩手県, 母親:人&{現在地:L}}).,q(人&{出生地:L, 現在地:L}).,型付素性構造では、複数の素性が同一の値を指し示す場合があります。これを構造共有と呼びます。,| ?- p(X), fs_writeAVM(X).,|~人 ~|,| 出生地:_58 |,| 母親: |~人 ~| |,| | 出生地:atom | |,| | 母親: 人 | |,| | 父親: 人 | |,| | 現在地:_58 | |,| |_ _| |,| 父親: 人 |,| 現在地:岩手県 |,|_ _|,X = 人&{出生地:_58,現在地:岩手県,母親:人&{現在地:_58}}.,yes,| ?- q(X), fs_writeAVM(X).,|~人 ~|,| 出生地:_40 |,| 母親: 人 |,| 父親: 人 |,| 現在地:_40 |,|_ _|,X = 人&{出生地:_40,現在地:_40}.,yes,単一化においては、それぞれの素性構造での構造共有の情報も伝えられます。従って、 p(X) と q(X) が同時に成り立つような X においては、「本人の出生地と母親の現在地が等しい」「本人の出生地と本人の現在地が等しい」の両方が同時に成立することになり、結果として次のような素 性構造が得られます。,| ? -p(X), q(X), fs_writeAVM(X).,|~人 ~|,| 出生地:岩手県 |,| 母親: |~人 ~| |,| | 出生地:atom | |,| | 母親: 人 | |,| | 父親: 人 | |,| | 現在地:岩手県 | |,| |_ _| |,| 父親: 人 |,| 現在地:岩手県 |,|_ _|,X = 人&{出生地:岩手県,現在地:岩手県,母親:人&{現在地:岩手県}}.,yes"}); htmllist.push({"file":"manuals/manual_tfs.html#Section10","title":"自然言語処理への応用","text":"自然言語処理への応用,ここでは、文法理論の一種である HPSG を用いた日本語の簡潔な解析例を示します。,HPSG は、個々の語彙に文法に関する制約が記され、単一化を通じて制約条件を満たすように句の形成が行われるという特徴を持つ理論です。,言語学的な情報が格納される基本的な単位となるのが sign 型の値です。ここには、音韻や統語、あるいは意味に関する情報などが含まれます (この例では意味情報は省略しています) 。sign 型の subtype として word 型、 phrase 型があり、それぞれ単語と句に対応します。,例として、「きつねが転ぶ」という文を解析してみます。,単語「きつね」に対応する型付素性構造は次のようになります (説明のため、 AVM は AZ-Prolog で出力される形式と多少異なる点があります) 。,|~word ~|,| PHONOLOGY:[きつね] |,| SYN: |~gram_cat ~| |,| | HEAD: 名詞& | |,| | COMPS:[] | |,| |_ _| |,|_ _|,格助詞「が」に対応する型付素性構造は以下の通りです。,|~word ~|,| PHONOLOGY:[が] |,| SYN: |~gram_cat ~| |,| | HEAD: |~格助詞 ~| | |,| | | FORM:が格& | | |,| | |_ _| | |,| | COMPS: [ | |,| | |~sign ~| | |,| | | PHONOLOGY:list | | |,| | | SYN: |~gram_cat ~| | | |,| | | | HEAD: 名詞& | | | |,| | | | COMPS:[] | | | |,| | | |_ _| | | |,| | |_ _| | |,| | ] | |,| |_ _| |,|_ _|,素性 PHONOLOGY は音韻に関する情報を表します。この例では語を表記の通りに格納することにします。,素性 SYN は gram_cat 型の値をとり、統語論的情報を格納します。gram_cat 型は素性 HEAD と素性 COMPS を持ちます。,素性 COMPS のリストには、とるべき補語が示されています。格助詞「が」の場合、素性 SYN の素性 COMPS は、名詞を表す sign 型の値を 1 つ持つリストです。したがって、格助詞「が」は、名詞「きつね」を補語としてとることで、次のような句を形成することができます。,|~phrase ~|,| PHONOLOGY:[きつね,が] |,| SYN: |~gram_cat ~| |,| | HEAD: |~格助詞 ~| | |,| | | FORM:が格& | | |,| | |_ _| | |,| | COMPS:[] | |,| |_ _| |,|_ _|,単語ではなく句を意味する素性構造なので、型は phrase 型になっています。,素性 PHONOLOGY から分かるように、これは「きつねが」に対応する句です。ここでは、素性 COMPS は空リストとなっています。すでに名詞「きつね」が補なわれたため、これ以上は語を補う必要がないことを示しています。補語に関する規則は、末尾に掲載したプログラムにおいて head_complement_schema 述語に記述されています。,次に、素性 SYN の素性 HEAD を見てみると、「格助詞」型となっています。ここには主辞 (head) の情報が納められています。主辞とは、句の中心的な文法的性質を決定する語です。句「きつねが」においては、格助詞「が」が主辞となっています。このため、格助詞「が」の素性 HEAD から句「きつねが」の素性 HEAD へと情報が引き継がれたのです。この規則を記述しているのが head_feature_principle 述語です。,このようにして、語彙に記された情報を手掛かりに、2 つの単語を組み合わせて句を形成することができました。,続いて、動詞「転ぶ」の素性構造を以下に示します。,|~word ~|,| PHONOLOGY:[転ぶ] |,| SYN: |~gram_cat ~| |,| | HEAD: |~動詞 ~| | |,| | | FORM:終止& | | |,| | |_ _| | |,| | COMPS: [ | |,| | |~sign ~| | |,| | | PHONOLOGY:list | | |,| | | SYN: |~gram_cat ~| | | |,| | | | HEAD: |~格助詞 ~| | | | |,| | | | | FORM:が格& | | | | |,| | | | |_ _| | | | |,| | | | COMPS:list | | | |,| | | |_ _| | | |,| | |_ _| | |,| | ] | |,| |_ _| |,|_ _|,先ほどと同様に考えて、素性 COMPS を確認すると「が格」の「格助詞」型の文法的性質を持つ値を補語として持つことが分かります。先ほどの句「きつねが」はこの条件を満たしていますから、「転ぶ」は「きつねが」を補語として取り、全体として次のような句を形成します。,|~phrase ~|,| PHONOLOGY:[きつね,が,転ぶ] |,| SYN: |~gram_cat ~| |,| | HEAD: |~動詞 ~| | |,| | | FORM:終止& | | |,| | |_ _| | |,| | COMPS:[] | |,| |_ _| |,|_ _|,日本語の完全な文の場合、主辞の値は終止形の動詞型が来ること、および補語がこれ以上満たされる必要がないことが要請されます (述語 root_condition がこれに対応する制約を与えています)。上の素性構造はこれを満たしています。,これで、文「きつねが転ぶ」の解析が完了しました。,実際のプログラムにおいては、構文木の親子関係に関する規則を処理したり、解析結果を保存したりするために素性 DTRS, HEAD_DTR, COMP_DTR を用いています。解析が終わると、構文木の根にあたる素性構造の素性 DTRS に全体の構文木が格納されています。詳しくはプログラムを実行して確認してください。,%%%%%%%%%%%%%%%,% HPSG types %%,%%%%%%%%%%%%%%%,form<-[bot].,fin_form<-[form].,verb_form<-[form].,終止<-[verb_form,fin_form].,未然<-[verb_form].,case_form<-[fin_form].,が格<-[case_form].,に格<-[case_form].,を格<-[case_form].,の格<-[case_form].,pos<-[bot]+['FORM':form].,動詞<-[pos].,格助詞<-[pos].,名詞<-[pos].,形容詞<-[pos].,gram_cat<-[bot]+['HEAD':pos,'COMPS':list].,head_struc<-[bot]+['HEAD_DTR':bot].,head_comp_struc<-[head_struc]+['COMP_DTR':bot].,sign<-[bot]+['PHONOLOGY':list,'SYN':gram_cat].,phrase<-[sign]+['DTRS':head_struc].,word<-[sign].,%%%%%%%%%%%%%%%%,% HPSG parser %%,%%%%%%%%%%%%%%%%,parse([X|Rest],Rest,_,Lex):-,lexicon(X,Lex).,parse(L1,L2,[_|X],Tree):-,parse(L1,L3,X,T1),,parse(L3,L2,X,T2),,principles(T1,T2,Tree).,input_phrase(PHRASE,TREE):-,parse(PHRASE,[],PHRASE,TREE).,input(SENTENCE,TREE):-,root_condition(TREE),,input_phrase(SENTENCE,TREE).,%%%%%,test_sentences(1,[きつね,が,転ぶ]).,test_sentences(2,[きつね,が,山,に,住む]).,test_sentences(3,[きつね,が,とんび,に,油揚げ,を,買わ,ない]).,test_sentences(4,[油揚げ,が,とんび,に,取ら,れる]).,test(N,Y):- test_sentences(N,X),input(X,Y),!,fs_writeAVM(Y).,%%%%%%%%%%%%%%%%,%% principles %%,%%%%%%%%%%%%%%%%,head_complement_schema(LEFT,RIGHT,HEAD,COMP,MOTHER):-,MOTHER={'SYN':{'COMPS':COMPS},'DTRS':{'HEAD_DTR':HEAD,'COMP_DTR':COMP}},,HEAD={'SYN':{'COMPS':[COMP|COMPS]}},,LEFT=COMP,,RIGHT=HEAD.,id_principle(LEFT,RIGHT,HEAD,COMP,MOTHER):-,head_complement_schema(LEFT,RIGHT,HEAD,COMP,MOTHER).,head_feature_principle(HEAD,MOTHER):-,MOTHER={'SYN':{'HEAD':X}},,HEAD={'SYN':{'HEAD':X}}.,phonology_principle(LEFT,RIGHT,MOTHER):-,LEFT={'PHONOLOGY':X},,RIGHT={'PHONOLOGY':Y},,MOTHER={'PHONOLOGY':Z},,append(X,Y,Z).,principles(LEFT,RIGHT,MOTHER):-,id_principle(LEFT,RIGHT,HEAD,_,MOTHER),,phonology_principle(LEFT,RIGHT,MOTHER),,head_feature_principle(HEAD,MOTHER).,root_condition({'SYN':{'HEAD':動詞&{'FORM':fin_form&},'COMPS':[]}}).,%%%%%%%%%%%%%,%% lexicon %%,%%%%%%%%%%%%%,noun_phrase({'SYN':{'HEAD':名詞&,'COMPS':[]}}).,lexicon(きつね,,word&{'PHONOLOGY':[きつね],'SYN':{'HEAD':名詞&,'COMPS':[]}}).,lexicon(山,,word&{'PHONOLOGY':[山],'SYN':{'HEAD':名詞&,'COMPS':[]}}).,lexicon(とんび,,word&{'PHONOLOGY':[とんび],'SYN':{'HEAD':名詞&,'COMPS':[]}}).,lexicon(油揚げ,,word&{'PHONOLOGY':[油揚げ],'SYN':{'HEAD':名詞&,'COMPS':[]}}).,lexicon(に,,word&{'PHONOLOGY':[に],'SYN':{'HEAD':格助詞&{'FORM':に格&},'COMPS':[NP]}}),:- noun_phrase(NP).,lexicon(が,,word&{'PHONOLOGY':[が],'SYN':{'HEAD':格助詞&{'FORM':が格&},'COMPS':[NP]}}),:- noun_phrase(NP).,lexicon(を,,word&{'PHONOLOGY':[を],'SYN':{'HEAD':格助詞&{'FORM':を格&},'COMPS':[NP]}}),:- noun_phrase(NP).,lexicon(住む,,word&{'PHONOLOGY':[住む],,'SYN':{'HEAD':動詞&{'FORM':終止&},,'COMPS':[{'SYN':{'HEAD':格助詞&{'FORM':に格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':が格&}}}] }}).,lexicon(買う,,word&{'PHONOLOGY':[買う],,'SYN':{'HEAD':動詞&{'FORM':終止&},,'COMPS':[{'SYN':{'HEAD':格助詞&{'FORM':を格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':に格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':が格&}}}] }}).,lexicon(買わ,,word&{'PHONOLOGY':[買わ],,'SYN':{'HEAD':動詞&{'FORM':未然&},,'COMPS':[{'SYN':{'HEAD':格助詞&{'FORM':を格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':に格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':が格&}}}] }}).,lexicon(取る,,word&{'PHONOLOGY':[取る],,'SYN':{'HEAD':動詞&{'FORM':終止&},,'COMPS':[{'SYN':{'HEAD':格助詞&{'FORM':を格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':が格&}}}] }}).,lexicon(取ら,,word&{'PHONOLOGY':[取ら],,'SYN':{'HEAD':動詞&{'FORM':未然&},,'COMPS':[{'SYN':{'HEAD':格助詞&{'FORM':を格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':が格&}}}] }}).,lexicon(取ら,,word&{'PHONOLOGY':[取ら],,'SYN':{'HEAD':動詞&{'FORM':未然&},,'COMPS':[{'SYN':{'HEAD':格助詞&{'FORM':に格&}}},,{'SYN':{'HEAD':格助詞&{'FORM':が格&}}}] }}).,lexicon(転ぶ,,word&{'PHONOLOGY':[転ぶ],,'SYN':{'HEAD':動詞&{'FORM':終止&},,'COMPS':[{'SYN':{'HEAD':格助詞&{'FORM':が格&}}}] }}).,lexicon(ない,,word&{'PHONOLOGY':[ない],,'SYN':{'HEAD':動詞&{'FORM':終止&},,'COMPS':[{'SYN':{'HEAD':動詞&{'FORM':未然&},'COMPS':COMPS}},|COMPS] }}).,lexicon(れる,,word&{'PHONOLOGY':[れる],,'SYN':{'HEAD':動詞&{'FORM':終止&},,'COMPS':[{'SYN':{'HEAD':動詞&{'FORM':未然&},'COMPS':COMPS}},|COMPS] }})."}); htmllist.push({"file":"manuals/manual_tfs.html#Section01","title":"型とその階層","text":"9-2-6. 型付素性構造の詳細,型とその階層,型は継承関係によって定義された階層構造を備えています。,図 1 では、三角形の種類についての型階層を表現しています。,図 1 三角形の階層関係, ,型の継承関係が線のつながりで表されています。例えば、二等辺三角形と直角三角形はどちらも三角形を継承しています。型が表す概念としては、上側に 行くほど特殊性が増し、下側に行くほど一般性が増しています。ある型を基準に、そこから線でたどれる上側の型 (自分自身を含む) を subtype と呼び、下側の型 (自分自身を含む) を supertype と呼びます。例えば正三角形は三角形の subtype となります。複数の型を継承することもできます。例えば、直角二等辺三角形は二等辺三角形と直角三角形の両方を継承しています。,このように、型階層を用いて概念の階層関係を表現することができます。一番下にある bot という型 (bottom の意味) は、最も一般的な型であり、すべての型は bot の subtype となります。"}); htmllist.push({"file":"manuals/manual_tfs.html#Section02","title":"型の定義と記述-->","text":"型の定義と記述,型を用いるためにはあらかじめ型定義を行っておく必要があります。,型定義は次のような書式で行います (素性を持つ型の定義方法は後で示します) 。,型 <- [型1, 型2, ...].,左辺の型が継承先、右辺の型が継承元です。型名として用いることのできる文字列の種類は、アトムに用いることのできるものと同一です。,右辺の型は、bot のような組み込み型を除き、すでに定義されている必要があります。つまり、型定義においては、上のほうの行で一般性の高い型を定義し、下に行くほど特殊性の高い型を定義することになります。,同じ型は 2 度宣言することはできません。左辺に同じ型が 2 度以上出現するとエラーになります。,型定義はトップレベルから行うことはできません。ファイル中に記述しコンサルトする必要があります。,図 1 の三角形の階層構造を AZ-Prolog で宣言すると以下のようになります。,三角形 <- [bot].,二等辺三角形 <- [三角形].,直角三角形 <- [三角形].,直角二等辺三角形 <- [二等辺三角形, 直角三角形].,正三角形 <- [二等辺三角形].,プログラム中で型を表すには、型名の後に '&' を付与します。たとえば、二等辺三角形の型は,二等辺三角形&,と表記されます。'&' が付与されない場合は単なるアトムとして解釈されます。なお、,二等辺三角形& = X.,などのように、型の直後に演算子を書く場合は、'&' と演算子の間にスペースを入れる必要があります。スペースを入れずに '&=' と書くと、まとまった単独の演算子として解釈されてしまいます。ただし、,X = 二等辺三角形&, X = 直角三角形&.,のような場合に登場する '&,' や '&.' という表記に関しては例外で、それぞれ '&' と ',' および '&' と '.' の 2 つの演算子の並びとして扱われます (fs_mode/2 述語で素性構造モードを 2 に指定した場合) 。つまり、上の例は,X = 二等辺三角形& , X = 直角三角形& .,と等価です。"}); htmllist.push({"file":"manuals/manual_tfs.html#Section03","title":"型の単一化","text":"型の単一化,型どうしの単一化とは、共通の subtype の中で最も一般的な型 を見つける処理に相当します。,先ほどの三角形の例でいえば、二等辺三角形と直角三角形を単一化すると直角二等辺三角形が得られます。三角形と二等辺三角形を単一化すると二等辺三角形が得られます。正三角形と直角三角形は共通の subtype を持たないため、この 2 つの型は単一化に失敗します。, ,| ?- X = 二等辺三角形&, X = 直角三角形&.X = 直角二等辺三角形&{}.yes| ?- X = 三角形&, X = 二等辺三角形&.X = 二等辺三角形&{}.yes| ?- X = 正三角形&, X = 直角三角形&.no,単一化した結果に {} が付いているのは、後述する型推論によるものです。,型階層を定義する際には、単一化した後の型は一意に決まるようにする必要があります。,図 2a において、 c と d はともに a と b の共通の subtype ですが、 c と d の間に継承関係は存在しないため、最も一般性を持つ subtype が決定できません。そのため、 a と b を単一化した結果となる型が一意に定まりません。このような階層構造は定義エラーとなります。,図 2a,% 図 2a に対応する型定義,a <- [bot].,b <- [bot].,c <- [a, b].,d <- [a, b].,c と d をともに a と b の共通の subtype としたい場合には、図 2b のように、まず e を、 a と b の唯一の単一化先として導入し、この e から c と d を継承するように定義する必要があります。,図 2b,% 図 2b に対応する型定義,a <- [bot].,b <- [bot].,e <- [a, b].,c <- e.,d <- e.,図 3 においては、b と c、 あるいは a と d などに関しては単一化の結果は一意に定まります。しかし、 a と b に関しては共通の subtype である e と f のうち、どちらがより一般性を持つか比較不可能なため、単一化する型が決定できません。,図 3,% 図 3 に対応する型定義,a <- [bot].,b <- [bot].,c <- [bot].,d <- [bot].,e <- [a, b, c].,f <- [a, b, d].,図 4 において a の直接の子は c と f であり、b の直接の子は d と e なので、これらの間に共通する型はありませんが、さらに継承関係をたどってみると、e と f がともに a と b の共通の subtype であることが分かります。しかし、e と f の間に階層の上下関係がなく、より一般的な型が決定できないため、このような階層構造は不適切です。,図 4,% 図 4 に対応する型定義,a <- [bot].,b <- [bot].,c <- [a].,d <- [b].,e <- [b, c].,f <- [a, d].,単一化先が 1 つしか存在できないということは、単一化によるバックトラックは必然的に発生しないことを意味します。"}); htmllist.push({"file":"manuals/manual_summary.html#a","title":"1-1.AZ-Prolog概要","text":"1-1. AZ-Prolog概要,AZ-Prologは、「ISO/DEC-10 Prolog」に準拠した、世界最速級の処理性能を誇る論理型言語Prolog処理系です。,Prologによる手軽なプログラム開発やデバッグの環境を提供する「インタプリタ」、インタプリタ上での実行を高速化する「バイトコード・コンパイラ」、さらに高速な単独実行プログラムの作成を実現する「C言語ソースコード・コンパイラ」、プログラムをWEBサイトとして公開可能にする「CGIインタプリタ」などを備えています。,豊富に提供される拡張機能(9章を参照)により、開発できるアプリケーションの幅や可能性はさらに広がりました。,また、64ビットOS対応により、OSの提供する広大なメモリ空間を利用することができるようになり、従来は解が求まらなかった巨大なプログラムも走らせることが可能となりました。,さらに、CPUのマルチコア化に伴い、その性能をフルに活用するため、プログラムを複数のプロセスに分散して並列で駆動するMPI(Message Passing Interface)ライクな仕組みを取り入れました。これにより、Prologプログラムをより高速に実行することが可能となっています。,AZ-Prolog用Eclipseプラグインを利用することにより、Prologプログラムの開発(ソース作成、ソース管理、デバッグなど)を効率よく、ビジュアルに行うことができます。また、デバッグ機能をPrologの学習に援用すれば、Prologプログラミングの特徴である、再帰・ユニフィケーション・バックトラックなどの振る舞いを容易に理解、習得することができます。, ,Version9以降において、Prologのデータ型(項)に素性構造型を追加しました。これにより、HPSGなどの単一化文法を容易に記述できるようになりました。,Version9.5以降において、型付素性構造型をサポートしました。,動作環境,OS,Win32/64(Windows 10/8/7)、Linux 32/64 (Ubuntu 16.04/14.04/12.04)、 Mac OS(v10.12 Sierra)、Mac OS X(v10.9 Mavericks, v10.10 Yosemite, v10.11 El Capitan),対応Cコンパイラ,Microsoft Visual Studio 2017/2015/2013、GCC,ハードウェア,上記OSが動作する環境。64ビット版では6Gバイト以上のメモリを推奨,ディスク容量,60MB以上,※Win32版は64ビットOS上でも動作しますが、Win64版は32ビットOSでは動作しません。 一部の拡張機能については外部ライブラリを利用している関係から、2015年現在、32ビット版のみ対応のものがあります(現状はCaboChaのみ)。,Mac版は、v10.9以上でないと動作保障の対象外となります。,32ビット版と64ビット版の主な相違点, ,32ビット版,64ビット版,セルサイズ,8byte,16byte,整数の範囲,-2147483648~2147483647(※1),e_register/3,repeat/1のとる値も同じ ,-9223372036854775808~9223372036854775807(※1),e_register/3, repeat/1のとる値も同じ,数値演算,-,整数と浮動小数点数(倍精度)の混在する計算結果は浮動小数点数になりますが、浮動小数点数の仮数部(52ビット)よりも整数の範囲が大きいため、大きな整数の演算では、計算結果が情報落ちすることがあります。,数値アレイ,1,2,4byte,1,2,4,8byte,ヒープ・スタックサイズ,合計最大2Gバイト,OSと実メモリの提供範囲,※1 整数の範囲を超えた数値を入力またはプログラム上に記述したとき,s_int_ovf_mode/2 で設定されたモード(デフォルトはon)により、,on の場合は 読み込み時にエラーとなり、offの場合はエラーにはなりませんが異なる数値になります。"}); htmllist.push({"file":"manuals/manual_summary.html#b","title":"1-2.マニュアルについて","text":"1-2. このマニュアルについて,1-2-1.マニュアルを読むために必要な知識,・Prolog言語の知識,AZ-Prologのシンタックスは「ISO/DEC-10 Prolog」に準拠していますので、その知識を前提とします。,このマニュアルの「4.Prolog言語」でもProlog言語について解説をしていますが、Prolog言語を全くご存じ無い方には少々説明が不足かも知れません。そこで、Prolog言語についての入門書を読みながらこのインタプリタを使っていかれることをお奨めします。,Prolog言語の入門書・解説書については次項の「1-2-2.Prolog言語に関する参考文献」で紹介します。,・OSの知識,各OSの基本的な使い方を始め、エディタの概念などは最低限知っている必要があります。また、AZ-Prologには、コマンドライン・ユーティリティーを実行出来る「system」述語と、一時的にOSのコマンド・プロンプトレベルに抜けられる「sh」述語などがあります。これらを使用する場合は、用途に応じた知識が必要です。,・Webサーバー、CGIの知識,AZ-PrologではPrologアプリケーションをCGIとしてWeb公開できる機能が実装されています。これらを利用するためには、Webサーバーの設定、CGIの知識が必要です。,1-2-2.Prolog言語に関する参考文献,(1)Prolog-KABA入門    柴山悦也・桜川貴司・荻野達也  著 岩波書店,(2)Prolog入門    古川康一 著 オーム社,(3)Prolog    中島秀之 著 産業国書,(4)Prolog入門    後藤滋樹 著 サイエンス杜,(5)知識指向言語Prolog    小谷善行 著 技術評論社,(6)Prologプログラミング入門    安部意広 著 共立出版,(7)Prologとその応用    溝口文雄  監修 総研出版,(8)はじめてのProlog    舟本奨 著 ナツメ社,(9)Prologの技芸    Leon Sterling、Ehud Shapiro 著 共立出版,(10)Prologで学ぶAI手法―推論システムと自然言語処理    高野真 著 啓学出版,(11)Prologで学ぶAIプログラミング    赤間 世紀 著 工学社,1-2-3.どの部分から読み始めるか,AZ-Prologを購入またはダウンロードされて、最初にサンプルプログラムを動かされると思います。,そのためにはまず「2.インストールと環境設定」に記述されているインストール方法の指示に従って、AZ-Prologの動作可能な環境を作ります。,インストールが終了し「3-2.やってみましょう」を参照されれば、サンプルプログラムを動かすことが出来ます。,その次にはご自分で簡単なプログラムを打ち込んで実行してみることでしょう。,プログラムを入力するには次の方法があります。,[1]外部のエディタを使って作成したプログラムをPrologに読み込む。,[2]コンソールから直接プログラムを入力する。,[3]標準のインタプリタに組込述語として内蔵されている、Prologプログラム向けのスクリーンエディタAzEditを使ってプログラムを入力し、そのエディタ・バッファの内容をインタプリタにプログラムとして直接転送する。,方法[1]と方法[2]は、「5-3.プログラムの入カ方法」で、方法[3]は「9-10.AzEditの使い方」でそれぞれ説明しています。,AZ-Prologの初版を開発した当時と比べ、現在では高機能なエディタが多くあります。,AzEditより使い慣れたエディタがあれば、そちらを使ってプログラムを入力する方が効率が上がると思われます。,従来からご使用頂いているユーザ様及びプログラムの互換性を考慮し、AzEditを付属しております。,用途に応じて、外部のエディタとAzEditを使い分けるとよりプログラムの開発効率が上がるようになります。,AZ-Prologに慣れてきたところで、デバッガを使ったり、組込述語の機能を調べ始めてください。,Prolog言語についてある程度知っておられる方や「Prolog」を使った経験がある方は、本システム独自の機能について必要に応じて参照してください。"}); htmllist.push({"file":"manuals/manual_summary.html#c","title":"1-3.表記規則","text":"1-3. 表記規則,1-3-1.ユーザが入力する部分,以下の例では、ユーザが入力する部分を表しています。,また、「↓」はCR(キャリッジリターン/Enter)キーを押すことを表します。,<例>,C:¥>Prolog↓,ここで「C:¥>」は、OSの対話型シェル(CMD.EXE等)レベルでコンソール(画面)に出力されるプロンプトであり、「Prolog↓」がユーザによって入力された(されるべき)文字列です。,また、ユーザが入力する部分に下線「_」が含まれる場合がありますので見落とさぬ様にご注意ください。,1-3-2.述語の表記,Prologでは述語名とアリティ(引数の個数)で特定の述語が決まります(述語名が同じでもアリティが異なれば違う述語として扱われます)。,そこで、特定の述語を表すのに[述語名/アリティ]という記法を用いています。,<例>,true/0,・・・,名前が「true」で引数が無い述語,リカイスル/2,・・・,名前が「リカイスル」で引数が2個の述語,また、演算子及び算術関数は、上記の様に引数とともに表記する場合と、以下の例のように[演算子または算術関数名/オペレータの型]という記法で表記する場合があります。,<例>,+ /yfx,・・・,引数が2個の中置演算子(X+Yのように用いる),- /fy,・・・,引数が1個の前置演算子(-Yのように用いる),1-3-3.コントロール・キャラクターと機能キー,例えば、キャラクター・コード(ASCIIコード)1のキャラクタを、「CTRL-A」のように表します。,また、コントロールキャラクタをキーボードから入力する場合は、「^」 を付けて表します。例えば、「CTRL-X」をキーボードから入力する場合は 「^X」と表します。,ただし,① 入力行を終了させるキー(キャリッジリターン),② 入力を終了させるキー,③ 中断キー,以上の3つの機能キーはオペレーティング・システムによって異ったり、オペレーティング・システムの中には個人の好みにより、端末毎にキー割当てが変更できるものもあります。,従って本書では混乱を避ける為、それぞれ以下の様に表記しています。,① 入力行を終了させるキー・・・END_OF_LINEキー,② 人力を終了させるキー・・・・END_OF_INPUTキー,③ 中断キー・・・・・・・・・・INTERRUPTキー,1-3-4.コメント,本文のプログラム中の「/* ・・・・ */」という文字列、またはある行の「%」以下はコメント文を表しています。,またコメント文ではありませんが、本マニュアルの中で説明文をプログラム中の「←」以下に書いてある所もあります。,注)実際のソースプログラムに「←」を書く事は文法上許されていません。,1-3-5.「¥」と「\」,JISキーボード以外のキーボードを採用している機種では、キャラクタコード[92]の「¥」はキートップ及び画面表示が「\」となります。,本マニュアルでは国内のパソコン及びワークステーションの多くがJISキーボードを採用していることから「¥」で統一するものとします。"}); htmllist.push({"file":"manuals/manual_setup.html#setup","title":"2-1.Windows","text":"2.インストールと環境設定,この章では、AZ-Prologのインストールと環境設定について、Windows版(2-1)とLinux版(2-2)、Mac版(2-3)の順に解説しています。,本マニュアルでは、OSによらずAZ-Prologがインストールされたディレクトリを ${AZProlog} と表記します。,2-1.Windows,2-1-1.インストール,Windows版のインストールの手順を説明します。,旧版のAZ-Prologがインストールされている場合、コントロールパネル→「プログラムと機能」で旧版用のプログラムを削除しておいてください。手作業で旧版用の環境変数を設定されている場合はこれを削除しておいてください。,Windows8等のAZ-PrologがサポートしているOSを起動します。,AZ-Prolog32ビット版は32ビットOSに、64ビット版は64ビットOSにインストールします。,OSに合わせた、64ビット、または32ビット用インストールファイルをホームページからダウンロードし、実行すると、インストールが開始されます。またインストールメディア(DVD-ROM)からインストールする場合は、ドライブに挿入すれば自動でインストールが開始します。,自動でインストールが始まらない場合は、エクスプローラからDVD-ROMのazprolog.msiを開きます。,インストール・プログラムが起動されると、インストール先の指定等の指示が表示されますので、その指示に従ってください。,インストールが終了すると、プログラムマネージャーにAZ-Prolog用のグループが追加され、AZ-Prologパッケージのプログラム等がスタートメニューに登録されます。,インストール後、インストールされたディレクトリの「relnote.txt」ファイルを確認してください。このファイルには、マニュアルには書かれていない追加事項などが記載されています。,2-1-2.環境設定,インストール時に、インストール先フォルダを変更しなかった場合は、以下のようにディレクトリが構成され、各ファイルが格納されます。また、構成されたディレクトリに環境変数が設定されます。,構成されたディレクトリ及びファイル,C:¥Program Files, ,├ ¥AZ-Prolog.9xx, ,├ ¥Bench,ベンチマークプログラム一式,├ ¥bin, ,├ prolog.exe,ウインドウ版インタプリタ,├ prolog_c.exe,コンソール版インタプリタ(並列処理子側プロセスと共用),├ prologcgi.exe,CGI用インタプリタ,├ azpc.exe,Prologコンパイラ,├ azserv.exe,OLEオートメーションサーバーPrologインタプリタ,├ ¥doc, ,├ ¥include, ,├ ¥lib, ,├ ¥ext,拡張機能動的リンクライブラリ,├ ¥obj, ,├ ¥sample, ,├ ¥system, ,※AZ-Prologのディレクトリ名はバージョンごとに変わります。インストールされたバージョンでの構成については、インストールディレクトリ直下のrelnote.txtを参照してください,環境変数は、次のように設定されます。,【構成されたディレクトリ 】,【設定される環境変数】,C:¥Program Files¥AZ-Prolog.9xx¥bin,このDIRがシステム環境変数Pathに追加される,C:¥Program Files¥AZ-Prolog.9xx¥lib,このDIRがシステム環境変数Libに追加される,C:¥Program Files¥AZ-Prolog.9xx¥include,このDIRがシステム環境変数Includeに追加される,C:¥Program Files¥AZ-Prolog.9xx ,このDIRがシステム環境変数AZPrologに設定される,Path OSがコマンド検索を行うときに参照するシステム環境変数で、AZ-PrologインタプリタやAZ-Prologコンパイラが存在するディレクトリもこれに定義しておかなければなりません。詳しくは各OSのマニュアルを参照してください。,Lib AZ-Prologコンパイラが使用する動的ライブラリ・ファイル「azp.lib」が存在するディレクトリを指定します。,このシステム環境変数は、リンカがライブラリを検索する時に参照します。詳しくはCコンパイラのマニュアルを参照してください。,lnclude AZ-Prologコンパイラが使用するヘッダファイル「azprolog.h」が存在するディレクトリを指定します。,このユーザー環境変数は、Cコンパイラのプリプロセッサーがインクルードファイルを検索する時に参照します。詳しくはCコンパイラのマニュアルを参照してください。,AZProlog,¥doc,このディレクトリ直下にエラーメッセージファイル「errmsg.pdf」があります。この環境変数が指定されていない場合は、実行ファイルと同じディレクトリにこれらのファイルが存在するものとみなします。,¥obj,このディレクトリ直下にAZ-Prologコンパイラのオプションスイッチ(「/i」「/no」「/curses」)を使用する時にユーザプログラムと一緒にリンクされるオブジェクトファイルディレクトリ「obj」があります。,この環境変数がない場合にはコンパイラはカレントディレクトリにあるものとみなして処理を行ないます。,¥system,このディレクトリ直下にAZ-Prologの拡張機能を提供するソースファイルがあります。,¥sample,このディレクトリにサンプルプログラムが格納されています。,¥bench,ベンチマークプログラムが格納されています。,インタプリタのベンチマークを計測する場合や再コンパイルする場合はプログラムをダウンロードしてください。ダウンロード先などの詳細はReadMe.txtに書かれています。,※環境変数の確認及び編集,<Windows7の場合>,Windowsスタートメニュー =>システムとセキュリティ=>システム=>設定の変更=>詳細設定=>環境変数,<Windows8/10の場合>,Windowsスタートメニュー(右クリック)=>コントロールパネル=>システムとセキュリティ=>システム詳細設定=>環境変数"}); htmllist.push({"file":"manuals/manual_setup.html#setup_2","title":"2-2.Linux","text":"2-2.Linux,2-2-1.インストール,ここではLinux版のインストールの手順を説明します。,Ubuntu 12.04 を起動します。,OSに合わせた、64ビット、または32ビット用tarファイルをホームページからダウンロードまたはDVDからコピーします。,ファイルを解凍します。,ダウンロード時に「プログラムで開く」を選んでOKすると、アーカイブマネージャが開きます。表示されたフォルダを選択して「展開」すると、指定したディレクトリに解凍されます。,それ以外の場合は、同様にアーカイブマネージャで展開までを行うか、以下のコマンドを実行してtarファイルを解凍してください。ダウンロード時に「ファイルを保存する」を選択した場合は、tarファイルはダウンロードフォルダに置かれます。解凍すべき場所に移動、もしくはコピーした上で行ってください。,$tar xzf azprolog9.xx-ubuntu12.04x64.tgz,解凍されたディレクトリに移動します。,インストールします。デフォルトでは、/usr/localにインストールされます。,他の場所にインストールするには、解凍ディレクトリのMakefileの下記の部分を書き換えてください。,<例>/home/az へインストールする場合,PREFIX = /home/az,ESCAPED_PREFIX =  /home /az,基本機能のみか、フル機能をインストールするかに応じて、以下のいずれかを実行してください。,・基本機能のみのインストールの場合,$sudo make install,・フル機能(Redis、Websocket)をインストールする場合,$sudo make install_full,2-2-2.環境設定,・標準インストールの場合,「2-2-1.インストール」でデフォルトの場所にインストールした場合は、以下のディレクトリ構成で各ファイルが格納されます。この時には環境変数の設定は不要です。,ただし、本マニュアルの記述では説明の都合上、環境変数AZPrologが設定されているものとして説明している箇所があります。その場合は /usr/localに置き換えて考えてください。,<例>,マニュアルの記述:,"-L ${AZProlog}/lib/azprolog/ext -l_socket",実際の意味:,"-L /usr/local/lib/azprolog/ext -l_socket", ,・任意の場所にインストールした場合,この場合は、ご利用に先立ち、環境変数 AZPrologにインストール先を設定する他、必要な環境変数を以下の例に倣って設定してください。,<例>/home/az へインストールした場合の環境設定,export AZProlog=/home/az,export LD_LIBRARY_PATH=${AZProlog}/lib:${LD_LIBRARY_PATH},export PATH=${AZProlog}/bin:${PATH},.bashrc に書き加えておくと毎回の手間が省けますが、複数の異なるバージョンのAZ-Prologをインストールした場合は、バージョン毎にシェルスクリプトを書いて、その中で環境変数をそれぞれに変えて設定して切り替えることもできます。,Linux版では、インストール後のディレクトリは以下のように構成されます。任意の場所にインストールした場合は、 /usr/local の部分をインストール先に読み替えてください。,ベンチマークプログラムのコンパイル、拡張機能の再コンパイルなどの作業を行う場合は、必要に応じて作業ディレクトリにコピーしておこなってください。,構成されたディレクトリ及びファイル,/, ,├ /usr, ,├ /local, ,├ /bin, ,├ prolog,ウインドウ版インタプリタ(画面制御述語可、プロンプト"?-"あり),├ prolog_c,コンソール版インタプリタ(並列処理子側プロセスと共用),画面制御不可。質問するときは、"?-"を入力する。,├ prologcgi,CGI用インタプリタ,├ azpc,Prologコンパイラ,├ /include, ,├ /lib, ,├ /azprolog, ,├ /ext,拡張機能動的リンクライブラリ,├ /obj,コンパイラによりリンクされるオブジェクトファイル,├ /share, ,├ /doc, ,├ /azprolog, ,├ /bench,ベンチマークプログラム,├ /sample,サンプルプログラム,├ /system,拡張機能を提供するソースファイル"}); htmllist.push({"file":"manuals/manual_setup.html#setup_3","title":"2-3.Mac","text":"2-3.Mac,2-3-1.インストール,ここではMac版の環境設定及びインストール手順を説明します。,Mac OS を起動します。,ホームページより最新版(AZ-Prolog ver9 for MAC)をダウンロードまたはDVDからコピーします。,ダウンロードファイルの形式は、仮想ディスクイメージ(*.dmg)です。,ダウンロードした仮想ディスクイメージファイルを展開します。,仮想ディスクイメージファイルをダブルクリックすると、仮想ディスクイメージファイルが展開(マウント)されてフォルダが開かれます。,環境設定シェルファイルを選択します。,環境設定シェルファイル(prolog_setenv.sh)を右クリック(control+クリック)し、「情報を見る」を選択するとシェルファイルの情報ウィンドウが表示されるので「このアプリケーションで開く:」の選択で「ターミナル」を選択します。,環境設定シェルファイルを実行します。,prolog_setenv.shをダブルクリックし、シェルを実行します。,シェルを実行すると「ターミナル」が表示されます。,※シェルの実行は1回のみ行います。(複数回実行しても影響はありません),ターミナルを閉じます。,上部メニューの「ターミナル」を選択し、「ターミナルを終了」を選択します。,AZ-Prologアプリケーションの登録を行います。,仮想ディスクイメージファイルが展開されてフォルダを開き、azprologアプリケーション(アイコンが表示されているazprolog)を選択し、表示されているApplicationsフォルダへコピーします。,(azprologをマウスで選択し、クリックした状態でApplicationsフォルダへマウスを移動させドラッグする),2-3-2.環境設定,ターミナル上でazprologのアプリケーションをコマンド・インタプリタとして起動する場合は環境設定を手動で行う必要があります。,※なお、上記「2-3-1.インストール」でprolog_setenv.shを起動するとユーザ環境設定ファイル(~/.profileや~/.bash_profile)に必要な環境設定を自動で行います。,[環境設定],$ export AZProlog=/Applications/azprolog.app/Contents/az_home,$ export DYLD_LIBRARY_PATH=/Applications/azprolog.app/Contents/az_home/lib,$ export PATH=$PATH:/Applications/azprolog.app/Contents/az_home/bin,※上記の環境設定をユーザ環境設定ファイル(~/.profileや~/.bash_profile)などに登録しておくと毎回ターミナル起動後に手動で環境設定を行う必要がなく便利です。,azprologアプリケーションのホームディレクトリは、/Applications/azprolog.app/Contents/az_home となります(インストールディレクトリとも呼びます) 。,構成されたディレクトリ及びファイル,/Applications, ,├ /azprolog.app, ,├ /Contents, ,├ Info.plist,プロパティ・リスト,├ /MacOS,シェルスクリプト,├ /Resources,リソース,├ /az_home,azprologホームディレクトリ,├ /bin, ,├ prolog,ウインドウ版インタプリタ(画面制御述語可、プロンプト"?-"あり),├ prolog_c,コンソール版インタプリタ(並列処理子側プロセスと共用),画面制御不可。質問するときは、"?-"を入力する。,├ prologcgi,CGI用インタプリタ,├ azpc,Prologコンパイラ,├ /include, ,├ /lib, ,├ /pkgconfig, ,├ /azprolog, ,├ /ext,拡張機能動的リンクライブラリ,├ /obj,コンパイラによりリンクされるオブジェクトファイル,├ /share, ,├ /doc, ,├ /azprolog, ,├ /bench,ベンチマークプログラム,├ /sample,サンプルプログラム,├ /system,拡張機能を提供するソースファイル,2-3-3.アプリケーションの起動,AZ-PrologがMacのアプリケーションフォルダ(Finderでは左側の「アプリケーション」を選択)に登録されているのでazprologをクリックします。,azprologがターミナルで起動されることを確認してください。,また、一旦ターミナルを開き、コマンド・インタプリタでazprologアプリケーションを起動することも可能です。,なお、アプリケーション起動でエラー(dyld: Library not loaded: libazp.dylib)が表示された場合は、環境設定に問題があるため上記「2-3-2.環境設定」の項を再度確認してください。,[ターミナル上でのアプリケーション起動例],$ prolog,$ prolog_c,$ azpc,2-3-4.注意事項,azpcアプリケーションでCソースやprologスクリプトなどをコンパイルし、作成されたバイナリファイルを実行する際は、AZ-Prologの動的ライブラリのパスを設定しておく必要があります。,※ライブラリのパスが設定されていないと「ライブラリが存在しない」などのエラーが出力されます。,AZ-Prologの動的ライブラリのパスは以下となりますので、共有ライブラリパスの環境変数(DYLD_LIBRARY_PATH)などに設定後、目的のプログラムを実行します。,/Applications/azprolog.app/Contents/az_home/lib,また、ベンチマークプログラムをコンパイルし実行する際もライブラリパスの設定が必要となります。"}); htmllist.push({"file":"manuals/manual_onoff.html#onoff","title":"3-1.概要","text":"3-1.概要,AZ-Prologが動作する環境が整ったところで、この章では手始めにサンプルプログラム(Nクィーン:N×Nのチェス盤上でクィーンをお互に干渉しないように並べていくパズルゲーム)をインタプリタで動かしてみます。,以下ではそれに必要な最低限の知識が書かれています。"}); htmllist.push({"file":"manuals/manual_onoff.html#onoff_2","title":"3-2.やってみましょう","text":"3-2.やってみましょう,3-2-1.インタプリタの起動と終了,本章の説明は、Windowsのコマンドプロンプトから起動する事を前提として書かれています。Linux版またはMac版をお使いの方は、適宜必要な読み換えを行ってください。,読み換えの詳細は「マニュアルの使い方【1】ユーザーズマニュアルについて」をご覧ください。,先ず、OSのコマンドレベルから,c:¥> prolog↓,と入力します(Windows版でスタートメニューからAZ-Prologを起動する場合は、この入力はいりません)。,すると、別ウィンドウが開き(Linux版では同じターミナル内で)、,AZ-Prolog Interpreter/Compiler Version 9.xx (Win64/x64),Copyright (C) SOFNEC CO., LTD. 1987-2016/xx/xx,というAZ-Prolog(インタプリタ)の起動メッセージに続いて,| ?-,というPrologのプロンプトが表れます。,これでAZ-Prologが起動して質問(Prologにおける実行命令)を受け付けられる状態(プログラムが実行可能な状態)になります。,AZ-Prologを終了してOSのコマンドレベルに戻るには「consult/1、halt/0 、halt/1」という述語を実行します。,| ?-halt.,この後、OSのプロンプトが出て、OSのコマンドレベルに戻ります。,また「halt/1」を実行するとその引数に設定した数値を結果コードに設定して終了します。,この値は例えばバッチファイル中でIFコマンドのERRORLEVEL条件で終了条件を判定することが出来ます。,3-2-2.サンプルプログラムの実行,(1)プログラムの読み込み,AZ-Prologが起動した所で早速サンプルプログラムを実行してみましょう。,インタプリタでPrologプログラムを実行するには、ソースプログラムをヒープ領域(プログラム領域)に読み込む必要があります(この読み込む作業をコンサルト「consult」といいます。コンサルトについては、後の章の「5-3-2.ファイルからのプログラム入カ」を参照してください)。,ここでは「queen.pl」というファイルを読み込みます。,このファイルは、Windows版/Linux版/Mac版ではそれぞれ、,Windows版:,%AZProlog%¥sample¥other,Linux版:,${AZProlog}/share/azprolog/sample/other,Mac版:,${AZProlog}/share/azprolog/sample/other,にあります。,カレントディレクトリにある場合は以下コマンドでファイルを読み込みます。,| ?-['queen.pl'].yes,カレントディレクトリにない場合は、以下の手順でファイルを読み込みます。,OSのコマンドレベルでAZ-Prologのホームディレクトリを確認します。,C:¥>echo %AZProlog% C:¥Program Files¥AZ-Prolog.9xx,Prologを起動し、組込述語(chdir/1)でカレントディレクトリーを,「queen.pl」があるディレクトリーに変更しファイルを読み込みます。,| ?-chdir('C:¥Program Files¥AZ-Prolog.9xx¥sample¥other'). yes | ?-['queen.pl']. yes,(2)プログラムの起動,Nクィーンのプログラムで8×8の場合(8クィーン)の解を求めてみましょう。,それには,?-q(8).↓,と入力すると以下の様に8クイーンの解を次々と出力するはずです。,| ?-q(8).,No.1,. . . . . Q . .,. . . . . . Q .,. . . . . Q . .,. . Q . . . . .,Q . . . . . . .,. . . Q . . . .,. . . . . . . Q,.,.,.,No.92,. . . Q . . . .,. Q . . . . . .,. . . . . . Q .,. . Q . . . . .,. . . . . Q . .,. . . . . . . Q,. . . . Q . . .,Q . . . . . . .,Total = 92,yes,| ?-"}); htmllist.push({"file":"manuals/manual_onoff.html#onoff_3","title":"3-3.起動時のオプション","text":"3-3.起動時のオプション,AZ-PrologをOSのコマンドレベルから起動する時、コマンドにオプションを付加する事により、ワークエリアの専有量や起動時読み込みファイルの指定ができる他、AZ-Prolog上のアプリケーションプログラムにも、任意のパラメータを渡す事が出来ます。,AZ-Prologではインタプリタ及びコンパイルしてできた単独実行プログラムの起動時のオプションとして次のものが指定できます。,3-3-1.ワークエリアのサイズ指定,アプリケーションプログラムによって当然ながらヒープ領域の専有量、及びその他の各スタック領域の使用量が異なります。,そこで起動時に動作させるアプリケーションプログラムに合せてそれぞれのサイズを指定することができます。,必要サイズの目安については、アプリケーションによる各スタックの最大使用量が分かる述語statistics/0の出力が参考になります。,マシンスタックについては、コンパイル時のみ指定できます。,-h Heap[セル数(キロ単位)],ヒープ領域(プログラム等の定義が入る領域)の大きさをセル数(キロ単位)で指定します。,-l LocalStack[セル数(キロ単位)],ローカルスタック(ローカル変数などが入る領域)の大きさをセル数(キロ単位)で指定します。,-g GlobalStack[セル数(キロ単位)],グローバルスタック(グローバル変数などが入る領域)の大きさをセル数(キロ単位)で指定します。,-a Atoms[セル数(キロ単位)],アトム領域(アトムと変数名の入る領域)の大きさをセル数(キロ単位)で指定します。,(32ビットOSの場合、1セルは8バイト、1ワードは4バイト、64ビットOSの場合、1セルは16バイト、1ワードは8バイト),3-3-2.起動時に読み込むプログラムファイルの指定,以下のオプションでは起動時にシステムに読み込むファイルなどが指定できます。,-r Restore[ファイル名],AZ-Prologが起動時にrestoreを行なうファイルを指定します。,-s See[ファイル名],AZ-Prologの起動時のカレント入力ストリームを指定します。,インタプリタのトップレベルで組込述語see/2を単独で呼び出した場合と同じく、ファイルで定義された節を順次読み込んでアサートします。読込みが終わるとカレント入力ストリームはコンソールに戻ります。,-c Consult[ファイル名],AZ-Prolog起動時にコンサルトされるファイルを指定します。,-sとの違いはDCG記法で書かれたソースをProlog節へ変換することです。DCG記法については「5-3-2.ファイルからのプログラム入カ」の最後にある,を参照ください。,-b Bytefile[ファイル名],AZ-Prolog起動時にロードされるバイトコードファイルを指定します。,3-3-3.文字コードの指定,-sjis,文字コードがShift-JISで入出力を行うことを指定します。,-euc,文字コードがEUCで入出力を行うことを指定します。,-utf8,文字コードがUTF8で入出力を行うことを指定します。,※文字コードを指定しない時はOS(Locale)情報をもとに自動セットされます。,3-3-4.アプリケーションパラメータ指定のオプション,起動後のアプリケーションパラメータ(アプリケーションにOSのコマンドラインから各種の設定値などのを渡す為の値)を渡すためのオプションが指定できます。, -p Param1 Param2 …,「-p」以降の並びをアプリケーションパラメータとして渡す。複数指定する場合は、空白で区切ります。(この値は「get_parameter/1」でアトムのリストとして取得できます),3-3-5.その他のオプション,-nologo,インタプリタ起動時のスタートアップメッセージ表示を抑制します。ユーザーアプリケーションでこのメッセージが出るのが不都合な場合にも指定します。,3-3-6.オプション設定例,<例1>,C:¥>prolog -h 10 -a 20 -p 10 20 30,ヒープを10キロセル、アトム領域を20キロセルに設定。,アプリケーションパラメータとして10 20 30を設定します。,「get_parameter/1」を実行するとその引数に[10,20,30]なるリストがユニファイされアプリケーションパラメータが取得できます。,ただし、この[10,20,30]の各要素は数値項ではなくアトム項です。「term_atom/2」を用いてそれぞれを数値項に変換する事も出来ます。,<例2>,C:¥>prolog -r prolog.bin -c prolog.ini,起動値後に「prolog.bin」をリストアして「prolog.ini」をコンサルトします。「prolog.ini」はPrologのソースファイルです。初期設定を行うファイル名に慣習として用いています。,3-3-7.ワークエリアオプション設定ファイル,インタプリタ、アプリケーションの起動ディレクトリに「prolog.def」ファイルがあると、これを読み込みワークエリア設定をおこないます。,ファイルは4つの数値をスペースで区切ったもので、順にアトムエリア、ヒープエリア、グローバルスタック、ローカルスタックのサイズをセル数(キロ単位)で記述します。,また、環境変数AZPrologの設定ディレクトリにこのファイルがあると全てに適用されます。適用順は以下のとおりです。,起動時オプション直接指定>起動ディレクトリ「prolog.def」ファイル>AZProlog設定ディレクトリ下(注)の「prolog.def」ファイル>デフォルトサイズ,デフォルトサイズはコンパイル時に指定されたサイズです。,この設定ファイルは、特にエリア指定オプションのできない(「/no」でコンパイルされた)アプリケーションとCGIで有用です。,注:Linux版の場合は、正確には${AZProlog}/share/azprologの直下です。但し、環境変数AZPrologはLinux版のデフォルトインストールではセットされていない可能性があります。その場合は/usr/localと読み換えてください。,Mac版の場合は、正確には${AZProlog}/share/azprologの直下です。なお、環境変数AZPrologは必ず設定されている必要があります。"}); htmllist.push({"file":"manuals/manual_program.html#program","title":"4-1.Prologのデータ構造","text":"4-1.Prologのデータ構造,Prologが扱うデータは、項(term)と呼ばれます。大きく分けると、項には単純項と複合項の2種類があります。,単純項はPrologの基本的なデータ型で、これ以上細かく分解出来ないようなデータを表します。,単純項には定数と変数があります。,複合項は、いわゆる配列のように、複数のデータを一括して扱うためのものです。,つまり、幾つかの項をまとめ上げて一つの複合項は作られます。,逆に、一つの複合項を分解して、その構成要素を取り出す事も出来ます。,複合項は、配列よりはるかに柔軟なデータ構造を扱えます。,「項」は次のように分類されます。,4-1-1.定数,定数とは、プログラムの実行中に値が変化しないような単純項です。,例えば、次のようなものが定数です。,110   0   -1.2   漢字   penguin   'this-is-a-constant',定数には、主として次の3つのものがあります。,[1]整数値,整数値の表現には次の3種類があります。,10進表現,0から9までの数字の列,N進表現,最初1文字が基数を表す0から9の数字で、2番目が引用符号「'」で、3番目以降に0から9までの数字の列が続くもの。,ただし、最初の1文字が0のときは、16進数と見なし、aからfまたはAからFの英文字が混じってもよい。,また、最初の1文字が0のときは2番目が引用符号「'」に代え、0xffffのように「x」でもよい。,文字キャラクタコードと制御コードの表現,・c'に続く'¥'を除く1文字はその文字コードを表します。,<例>,| ?- A = [ c'a, c'A, c'%, c' , c',,c'あ ].,A = [97,65,37,32,44,33440],yes,・c'¥¥ は ¥の文字コードを表します。,<例>,| ?- A is c'¥¥ .,A = 92,yes,・c'¥ に続く次の1文字は制御コードを表します。これ以外はエラーとなります。,b,backspace,(character code 8),t,horizontal tab,(character code 9),n,newline,(character code 10),v,vertical tab,(character code 11),f,form feed,(character code 12),r,carriage return,(character code 13),e,escape,(character code 27),d,delete,(character code 127),a,alarm,(character code 7),<例>,| ?- X = [ c'¥b ,c'¥t ,c'¥n ,c'¥v ,c'¥f ,c'¥r ,c'¥e ,c'¥d ,c'¥a ].,X = [8,9,10,11,12,14,27,127,7],yes,| ?-X is c'¥A.,Syntax error,【プログラムコンサルト時、READ時の整数値オーバーフロー】,プログラムに記述された整数値や実行時に読み込まれる整数値は整数の有効範囲でなければなりません。,32ビット版 -2147483648~2147483647,64ビット版 -9223372036854775808~9223372036854775807,これを超える場合はエラーとなりますが、エラーとしたくない場合、組込述語 s_int_ovf_mode/2で抑止できます。,| ?-read(X).,|: 0xfffffffffffffffffffffff.,Illegal argument supplied ---- Backtrace,read(X_12) ?-,| ?-s_int_ovf_mode(_,off).,_.2 = on,yes,| ?-read(X).,|: 0xfffffffffffffffffffffff.,X = -1,yes,[2]実数値,実数は仮数と指数に分けて表現される数です。仮数と指数は「e」か「E」で区切ります。,指数が「1」の場合は「e」か「E」の区切りと指数を省略できます。,[3]アトム,アトムとは、以下の条件の何れかにあてはまる定数を指します。,英数字、仮名漢字、及びアンダーラインを組み合わせた文字列で、先頭の文字が英小文字または仮名漢字で始まるものです。,引用符号「'」(シングルクウォート)で囲まれた文字列、ただしこの文字列中に「'」自身を入れたい時は「''」のように続けて2回書く必要があります。,「+」「-」「*」「/」「¥」「^」「,」「=」「`」「:」「.」「?」「@」「#」「$」「&」からなる文字列。ただし、最初の2文字が「/*」でないもの(「/*」は、コメントの始まりを表します)。,「;」「!」「[]」「{}」「¦」のうちのどれか。,なお、アトムの長さは65,535文字以下でなければなりません。,4-1-2.変数,変数とは、プログラムの実行前に値を持っていない(未決定の)単純項です。変数は、潜在的に任意の項を値としてとりえます。,変数と見なされる文字列の条件は次の通りです。,英大文字またはアンダーライン「_」一文字か、これらで始まり、英数字、仮名、漢字などの全角文字及びアンダーラインより構成される文字列(これら以外の記号が含まれる事は許されません)。このうちアンダーライン「_」一文字の変数を虚変数と呼びます。この虚変数に代入された値(項)は参照できません。虚変数は同一節に複数出現したとしても異なる変数とみなされます。したがって、虚変数は複合項のアリティを合せる為のダミー変数としても使われます。,変数名の長さは65,535文字以下でなければなりません。また、1つの節の中で使用できる変数の数は65,535個以下となります。,4-1-3.定数と変数の有効範囲,定数(または変数)の有効範囲とは、プログラム中で2つ以上の同じ名前の定数(または変数)が常に同じものを意味する範囲のことです。,話を具体的にするために、下のプログラムに注目してください。,| 理解する(松尾さん,ワビ).↓ /*松尾さんは“ワビ”がわかる。*/,| 理解する(松尾さん,サビ).↓ /*松尾さんは“サビ”がわかる。*/,| 理解する(ブリキ屋さん,サビ).↓ /*ブリキ屋さんは“サビ”がわかる。*/,| 理解する(X,風流):- 理解する(X,ワビ).↓ /*“ワビ”がわかる人は風流を理解する。*/,| 理解する(X,風流):- 理解する(X,サビ). /*“サビ”がわかる人は風流を理解する。*/,この中には「松尾さん」というアトムが2ケ所に出現します。,すなわち「理解する(松尾さん,ワビ).」の中と「理解する(松尾さん,サビ).」の中です。,この2つの「松尾さん」は同一人物「松尾さん」を意味します。,別の言い方をすれば、この2つの「松尾さん」は全く同じものを表わしています。,もし、最初の「松尾さん」を別のアトム「芭蕉さん」で置き換えればこのプログラムは全く異なる挙動を示すでしょう。,一方、このプログラム中に変数Xは4ケ所出現します。,すなわち、,| 理解する(X,風流):- 理解する(X,ワビ).,の中に2ケ所と,,| 理解する(X,風流):- 理解する(X,サビ).,の中に2ケ所です。,ところが、この4つのXはすべて同じものを意味する必要はありません。,最初の節の2つのXは同じもの(例えば「松尾さん」)を意味しなければいけませんし、2番目の節の2つのXも同じもの(例えば「ブリキ屋さん」)を意味しなければいけません。,しかし、最初の節のXと2番目の節のXは別のもの(例えば前者が「松尾さん」で後者が「ブリキ屋さん」)を意味しても一向にかまわないのです。,実際、,| 理解する(X,風流):- 理解する(X,ワビ).,の中のXを、別の変数「Y」で置き換えて、,| 理解する(Y,風流):- 理解する(Y,ワビ).,としても、プログラムは同じように動くはずです。,つまり、同じ名前の定数はプログラム全体で同じで、ある決まったものを意味しますが、同じ名前の変数は1つの節の中でだけ同じで、まだ決まっていない何かを意味するのです。,したがって、定数の有効範囲はプログラム全体に及びますが、変数の有効範囲は1つの節の中にしか及びません。,余談ですが、上のプログラムで最初の「サビ」は抽象的概念としての「寂」を意味し2番目の「サビ」は金属が酸化してできた「錆」を意味すると考えるのが自然でしょう。すると、このプログラムは定数の有効範囲を誤って作られたことになります。,(勿論、「寂」を理解するブリキ屋さんもいらっしゃるでしょうが・・・),4-1-4.複合項,複合項は、いくつかの項を組み合わせて作られたものです。,複合項は本質的に述語形式で表現できます。したがって、述語形式以外の複合項でも、すべて述語形式で表現することが出来ます。,複合項の一般論として、複合項は他言語における関数とは異なり、複合項自身は値を持っている訳ではありません。,例えば「a(1,2) = 7.」として「a(1,2)」自身に「7」を代入するものではありません。,「a(1,2)」は単に「a」という名前の値が二つ入る入物に「1」と「2」が入ったものと考えてください。,複合項には、以下の3つの形式があります。,述語形式(ファンクタ、述語),演算子形式,リスト形式(リスト、ストリング),以下、順に説明します。,Ⅰ.複合項・述語形式(ファンクタ、述語),述語形式の複合項は、一般的な手続型言語における関数呼び出し形式と同様の記法を用いて書き表されます。,<形式>,述語名,(引数1,引数2,引数3,・・・・引数n), ,┃,┗━ 引数の数nをアリティという(0 < n ≦ 65,535 とする), ,述語名はアトム,<例>pair(リンゴ,apple),f(2,3,5),zoo(パンダ,ペンギン,カバ),'A'((b(1),v(2))),データ(A,M),名前(山田),※述語名を「ファンクタ」または単に「述語」とも呼び、引数を「アーギュメント(argument)」と呼ぶ場合もあります。,また、述語の引数の個数をアリティと呼びます。,Ⅱ.複合項・演算子形式,演算子形式の複合項は、アリティ(述語の引数の個数)が1または2の述語形式の複合項をオペレータ宣言して、数式のような記法を可能にしたものです。,<形式>「引数1 演算子 引数2」 「演算子 引数」 「引数 演算子」,例えば、「X is 1 + 2」も実は「is(X,+(1,2))」という述語形式の複合項と等価なのです。,つまり演算子は述語名にあたります。よって演算子は全てアトムです。アリティが1の場合も同じです。「spy p」は「spy(p)」と等価です。また、節の中のゴールの区切りである「,」や「;」も演算子の一種です。,オペレータ宣言の詳細については「4-3-5.オペレータ」を参照してください。,Ⅲ-(1).複合項・リスト形式 - リスト,リスト形式の複合項は、要素となる項の並びをカギカッコ(「[」と「]」)で囲ったもので、要素の数は可変長で、多くの手続型言語における配列のように予め要素の数を宣言する必要がなく、リストを繋いで要素を追加したり、分割して取り除いたりという操作が自由に出来ます。,<形式> [要素1,要素2,要素3,・・・要素n],リストの要素は通常「,」(カンマ)で区切られますが、区切り記号「|」(バーチカルライン、縦棒)で区切った場合は特別の意味を持ちます。リスト同士をユニファイする場合には、「|」の前までは対応する位置の要素同士がユニファイされますが、「|」の後の部分は残りの要素のリストがユニファイされます。,<例>,| ?-[X,Y|Z]=[a,b,c,d,e].X = a,Y = b,Z = [c,d,e],リストも実は述語名がピリオド「.」、アリティが2の述語なのです。,つまり、 [a,b,c,d] は .(a,.(b,.(c,.(d,[])))) と等価です。,最後の「[]」は空リストと呼ばれ、リストの最後の要素は通常は空リストになっていますが、カギカッコで括った表現では最後の空リストは見えません。,ただし、[a,b,・・・|x]と書いた場合に限り「x」がリストの最後の要素となり、この場合は空リストは見えないのではなく存在しません。,Ⅲ-(2).複合項・リスト形式 - ストリング,ストリングとは、「"」(ダブルクォート)以外の任意の文字を「"」で囲んだもの、または「""」のみからなる文字列(長さ0でもよい)です。,<形式>"任意の文字の並び",「"」自身を文字列に入れる場合は「""」とします。,例えば 「コレハ"カバ"デス」という文字列をストリングとして扱うためには「"コレハ""カバ""デス"」と書かなければいけません。,<例>"Panda" "漢字" "200" "I Know Prolog.",また、ストリングの実体は文字コードのリストです。,例えば、"Panda" は [80,97,110,100,97] と等価です。,漢字などのマルチバイト文字の場合も、通常使用されるエンコードに応じた漢字コードのリストになります。,例えば、"漢字" は、Shift_JISコード(2バイト文字)では [35519,36506] となり、UTF-8コードでは [15121570,15052183]となります。,ただし、漢字モードが「off」の場合は、1バイトずつに分けて扱われます。従って、"漢字" はShift_JISなら [138,191,142,154] 、UTF-8なら [230,188,162,229,173,151] となります。,<形式2>"任意の文字の並び"変数,ストリングに続き変数を記述すると文字コードリストの尾部変数となります。,<例>,| ?- X="Panda"L.,X = [80,97,110,100,97|L_13],,L = L_13,yes,Ⅲ-(3).複合項・素性構造型,素性構造型とは、,の集合です。AZ-Prologでは、ICOTで開発されたProlog処理系、CU-Prolog,CILのシンタックスを採用し、中括弧に挟まれた任意の個数の,をカンマで並べた表記をとります。,空を除き,を一つも要素としない場合は従来構造として扱いますのでDCGの補強項も問題なく記述できます。,とそれ以外の項との混在はエラーです。,また、素性は同一階層においてはユニークで、アトムでなければなりません。,はアトムである素性と区切り記号(デフォルトでは":" 変更可)で接続した素性構造型を含む任意の項で表します。,デフォルトでは素性構造を取り扱いますが、上記に抵触するようなプログラムの場合は、素性構造を取り扱わないモードへの切り替えも用意されています。, ,<素性構造の例>,{} %% 空の素性構造,{ 氏名:山田太郎,生年月日:{年:1951,月:5,日:26},趣味:X },・この素性構造は属性値行列(attribute value matrix、AVM)で次のように表記されます。,|~ 氏名 山田太郎 ~|,| |,| |~ 年 1951 ~| |,| 生年月日 | 月 5 | |,| |_ 日 26 _| |,| |,|_ 趣味 X _|,<素性構造でない従来型中括弧構造の例>,{write(X),nl},<エラーとなる例>,{ category:noun_phrase, category:verb_phrase } 同じ階層に同一素性が含まれている,{ category:noun_phrase,A } とでない項とが混在している,{ category:noun_phrase,Z:single } 素性がアトムでない項が含まれている,素性構造の単一化など詳細は、本マニュアル 9-2.素性構造型(Feature Structure型)に書かれていますのでご参照ください。,4-1-5.ストリーム値,オープンされていて入出力が可能なファイル(コンソールなどのデバイスを含む)を「ストリーム」と呼びます。,「ストリーム値」とは一般のファイル名の事ではなく、入出力ファイルを識別するための内部値です。,<表示形式>fp_XXXXXX,下の例からも分かるように、ストリーム値はこのような形式をしていますが、いわゆるファイルポインタと同様に考えればよく、自分で値を決める性質のものではありません。,ストリーム値は「see/2」「tell/2」「tella/2」によって入出力オープンした場合にこれらの述語の第2引数にユニファイされます(返される)。以降、ストリーム指定の出来る入出力述語(「read/2」「write/2」「writeq/2」「get0/2」「get0/2」「put/2」「listing/2」)を使う場合にファイル名の代わりにこのストリーム値で指定します。,なお、この値はアトムでないため、アトムレジスタへの保存することはできません。また、この値に分解・結合などの操作を加えることは許されず、意味がありません。,<例>‘abcde’というアトムを‘abc.txt’というファイルに書き込む。,¦?-tell('abc.txt',S),write(S,abcde),told(S).,S = fp_885f40,yes,4-1-6.アレイ,AZ-Prologで扱えるアレイは、任意の項を格納できる「項アレイ」、および、指定したバイト数の整数値を格納する「整数アレイ」のいずれかの配列型です。アレイのサイズは生成時に指定し、固定です。,アレイのインデクス(要素の位置を示す整数)は0から始まります。,大域的な領域が確保され、アレイのインデクスを指定してデータを設定、取得することができます。,「assert」「retract」と同様、述語呼び出しの副作用として値が設定変更されるので、バックトラックによって取り消されることはありません。,参考:,create_array/2,項アレイの生成,create_array/3,整数アレイの生成,set_array/3,アレイに値を設定,get_array/3,アレイから値を取得,array_register/3,arrayレジスタの値を取得・変更,<例>,| ?-create_array(100,Array),set_array(Array,0,a(1)),get_array(Array,0,V).,Array = array_57081856,V = a(1),yes"}); htmllist.push({"file":"manuals/manual_program.html#program_2","title":"4-2.プログラム","text":"4-2.プログラム,Prologのプログラムは下記の (1) または (2) の形をしたものからなります。,これらを節(「ホーン節」と呼ばれることもあります)と呼びます。,プログラムには、このように「規則」と「事実」と呼ばれる形式があり、「規則」は「頭部」と「本体」に別れます。,(1),<項>,:-,<項>(ゴール)の並び<終止符>,・・・,規則, ,頭部, ,本体(ゴール列), ,(2),<項>,<終始符>,・・・,事実, ,頭部, ,ただし、ここで各 <項> はアトムまたは複合項です(これらの一部が変数であってもその値がアトムまたは複合項ならば許されます)。,<終止符>はピリオド「.」とキャラクタコードが32以下の文字の二文字からなる文字列です。通常はピリオド「.」とキャリッジリターンとの組合わせで使い、ソースファイルは一行に複数の節を書く事はしませんが、文法上は例えばキャリッジリターンの代りにスペースでもよいので、一行に複数の節を書く事も許されます。,(1)の<項>と(2)の最初の<項>をこれらの節の頭部と呼びます。,また、(1)の二番目以降の<項>の列をこの節の「本体」または「ゴール列」と呼びます。そして、ゴール列中の各<項>を「ゴール」と呼びます。,(2)の形の節は「事実」と呼ばれる節で(1)の形の節の本体がない特別のものと考えることもできます。,次のものは(2)の形の節です。,| 理解する(松尾さん,ワビ).↓| 理解する(松尾さん,サビ).,これらの場合、「理解する」を「述語名」(または「述語」)と呼びます。より正確には、<頭部>または<ゴール>がアトムである時はそのアトム自身を、複合項の時はそのファンクタを述語名(または述語)といいます。,「松尾さんはワビを理解する。」という日本語の文章を考えた場合、「理解する」の部分が述語(または述語名)と呼ばれますから、この命名は自然なものであるといえます。,また、同じ述語名とアリティの頭部を持つ節の集りをこれまた述語と呼ぶ事もあります。,ここでは単に「述語」と呼んだ場合、特に断わりが無い限りは「同じ述語名とアリティの頭部を持つ節の集り」を指すものとします。,また、次のものは(1)の形の節です。,| 理解する(X,風流):- 理解する(X,ワビ).↓| 理解する(X,風流):- 理解する(X,サビ).,最初の節の頭部は「理解する(X,風流)」で、その述語名は 「理解する」 です。また、このゴールは「理解する(X,ワビ)」で、その述語名はやはり「理解する」です。,この節は「Xがワビを理解するならば、Xは風流を理解する」または「Xが風流を理解するためには、Xがワビを理解すればよい」と読みます。,このように、規則は「条件付の事実」と考える事ができ、ゴールはその条件に相当します。,つまり「Xがワビを理解する」という事象が真である(つまり条件が満たされる)時、「Xは風流を理解する」という事象が真(つまり「事実」)となることを表します。,Prologのプログラムはそれ自身が事象を表しています。,ゴールは「~ならば」という条件を表し、頭部は「~は~である」という事実を表します。,従って、ゴールのある(条件付の)節は条件が満たされるならば正しいという「規則」(ルール)であり、逆にゴールの無い頭部だけの節は文字通り無条件に正しい「事実」と言える訳です。,そして、ついでに言えばプログラムの実行はその事象が「真」か「偽」か(正しいかどうか)を調べる事なのです。,一般に、節が次の形をしているとすると、,<頭部>:-<ゴール1>,<ゴール2>,……,<ゴールn>.,これは、,<ゴール1>,<ゴール2>,……,<ゴールn>,がすべて正しければ<頭部>は正しい、または<頭部>の条件を満たすためには、,<ゴール1>,<ゴール2>,……,<ゴールn>,の条件がすべて満たされればよいと読む事が出来ます。,したがって、もし次のような節があれば、,| 理解する(X,風流):-理解する(X,ワビ),理解する(X,サビ).,これは「Xがワビを理解し、かつサビも理解するなら、Xは風流を理解する」という意味になります。,一方、もし次のような節があれば、,| 理解する(X,風流):-理解する(X,ワビ);理解する(X,サビ).,これは、「Xがワビを理解するか、あるいはサビを理解するなら、Xは風流を理解する」という意味です。つまり、ゴールを 「,」で区切ると「~かつ~(英語のand)」という意味が生じ、「;」で区切ると「~または~(英語のor)」の意味が生じる訳です。,また、「;」を使うかわりに、,| 理解する(X,風流):- 理解する(X,ワビ).↓,| 理解する(X,風流):- 理解する(X,サビ).,と2つの節を並べて書く事もできます。どちらの書き方をしても実行結果は、ほぼ変りません。,「;」を用いた方が簡潔に書けますが、「;」を多用するとプログラムが見にくくなり実行過程が把握しにくくなりますし、どちらかというと二つの節に分けて並べて書いた方が「Prologらしい書き方」と言えるかも知れません。,プログラムが書けたら、これを実行しなければ意味がありません。,プログラムを起動するためには、次の(3)または(4)の形のゴール列を入力してやればよいのです。,(3) :-<ゴール>,<ゴール>,……,<ゴール><終止符>,(4) ?-<ゴール>,<ゴール>,……,<ゴール><終止符>,(3)の形のゴールの並びを「コマンド」,(4)の形のゴールの並びを「質問」と呼びます(この違いは「質問」はその真偽を「yes」「no」で画面に表示するのに対し、「コマンド」はそれらを表示しない点だけです)。,どちらの場合にも、プログラムが実行される事(すべての<ゴール>が正しいかどうか調べられる事)には変りありません。,プログラムの実行については「4-3.プログラムの実行」を参照してください。,自然言語の文法規則を表現するDCG形式の記述も可能(その良い例としては、CGIのサンプルプログラムに「積み木の世界」があります。sample/cgi_demo/cgi-bin/tumiki.dcgを参照してください)ですが、コンサルト時に前述の規則/事実いずれかの節の形に変換されます。これについては「5-3-2.ファイルからのプログラム入カ」の最後にある,も参照してください。DCGの詳細については他書に譲ります。"}); htmllist.push({"file":"manuals/manual_program.html#program_3","title":"4-3.プログラムの実行","text":"4-3.プログラムの実行,「4-2.プログラム」で説明した通り、Prologのプログラムの実行は節によって表現された事象が正しいかどうか(真か偽か)を調べる(証明する)事が主目的です。,手続型言語に於ける手続き(例えば、画面に文字を表示する、数式の解を求めるなど)はPrologでは事象の証明過程の副作用と見なします。,勿論、実際にはその副作用が主目的である事の方が多いのですが、Prologプログラムを実行する側(つまり処理系側)から見れば証明が主目的で、手続きはその過程の一部として、しかたなく行なわれる作業です。,例えば,write('あいうえお'),というゴールがあったとすると、処理系はそのゴールの証明に取り掛かります。,「write/1」という頭部を持つ節は標準組込述語(処理系が予め内部的に持っている述語)として登録されているためそれを実行することになります。,組込述語の多くは所定の副作用を持っていて、処理系が証明過程(プログラムの実行過程)でそのゴールを調べようとすると、その副作用が実行されるようになっています。,「write/1」の場合はその述語名の通り、引数の項を出力する副作用を持っていて、その副作用(項の出力)を完了すれば「真」になります。,また組込述語の場合は、その個々の副作用の性格により証明(実行)結果として「真」「偽」の他に「エラー」が加わる述語もあります。,通常は実行時エラーが発生するとその時点で実行が中断されます。,このようにPrologプログラムの実行過程はすべて「証明過程」であると言えます。,ここにPrologが「論理型言語」と呼ばれる所以(ゆえん)があります。,4-3-1.単一化(ユニフィケーション、ユニファイ),ある2つの項に対し、それらが等しいかどうかを調べたり、それらの中に未代入の変数が出現する場合には、その変数に適当な項を代入してその2つの項が等しくなるようにしたりすることをユニフィケーション、またはユニファイ、または単一化と呼びます。,ユニファイには次の4つの場合の規則が考えられます。,二つの項がどちらも定数(または定数が代入された変数)の場合、双方の定数が等しければユニファイが成功し、等しくなければ失敗します。,二つの項のうち、どちらか一方が定数(または定数が代入された変数)で、他方が未代入の変数の場合、未代入の変数に定数が代入されて、ユニファイは必ず成功します。,二つの項がどちらも未代入の変数の場合、ユニファイが必ず成功し、その節内に於いてこれらの変数は同じ変数として扱われます。つまり、どちらかの変数に定数が代入されると他方の変数にも同じ値が代入されます。,複合項同士の場合、まずファンクタとアリティを調べ、もし違えばユニファイは即失敗します。それらが同じであった場合はその引数のユニファイに掛ります。,複合項の引数のユニファイは、並び順で対応する個々の引数同志について上記規則を再度適用することになります。そして、全ての引数のユニファイが成功に終った場合にのみ複合項のユニファイが成功し、それ以外は失敗します。,例えば,理解する(ブリキ屋さん,サビ),という複合項と,理解する(X,サビ),という複合項のユニファイをしたならば、先ず「理解する」が同じである事が確認(ユニファイ)されます。,次にどちらの複合項もアリティが2である事が確認されます。,それらが確認されたら、引数の値(「ブリキ屋さん,サビ」と「X,サビ」)のユニファイに取り掛かります。,先ず、第一引数の「ブリキ屋さん」と「X」のユニファイを試みます。,「X」が未代入の変数であるとすると、上の「2.」の規則にしたがって「X」に「ブリキ屋さん」が代入されて「ブリキ屋さん」と「X」のユニファイは成功します。,次に第二引数が「サビ」と「サビ」なのでユニファイは問題無く成功します。,この結果、「ファンクタ」「アリティ」「引数の内容」ともにユニファイが成功したので、「理解する(ブリキ屋さん,サビ)」と「理解する(X,サビ)」とのユニファイは成功し、「ブリキ屋さん」が「X」に代入されます。,理解する(ブリキ屋さん,サビ),|   |    |,理解する( X ,    サビ),また「理解する(松尾さん,X)」と「理解する(Y,サビ)」とをユニファイすると、その結果、「X」に「サビ」を、「Y」に「松尾さん」を代入してユニファイは成功します。,4-3-2.Prologの実行,Prologプログラムはどうやって実行されるのかを考えてみましょう。,Prologプログラムの実行は一言で云うと「ある事象が正しいかどうか(事実かどうか)を調べる(判断・判定する)過程」となります。,また、Prologプログラムは「~は事実か?」という質問で起動されます。,プログラムの具体的な例として次のプログラムを考えてみます。,[1] | 理解する(松尾さん,ワビ).↓[2] | 理解する(松尾さん,サビ).↓[3] | 理解する(ブリキ屋さん,サビ).↓[4] | 理解する(X,風流):- 理解する(X,ワビ).↓[5] | 理解する(X,風流):- 理解する(X,サビ).,まず、次の質問(頭部の無い本体{ゴール列}のみの節)を入力した場合を考えてみましょう。,[6] | ?-理解する(松尾さん,風流).,この時Prolog処理系は、[6]のゴールが正しいかどうか判定に行きます。,一般にあるゴールが正しいかどうか判定することを、ゴールの実行と呼びます。,[6]のゴールを実行するために、Prolog処理系は「理解する(松尾さん,風流)」とユニファイできる頭部を持った節を上から順番に探索します。,今の場合、まず[4] の節が探しだされるでしょう。,[6]のゴールとユニファイすることにより、[4]は次の[4']になります。,[4'] 理解する(松尾さん,風流):-理解する(松尾さん,ワビ).,[6]の質問の意味は「松尾さんは風流を理解するか?」です。そして、[4']の節の意味は「松尾さんが風流を理解するためには、松尾さんはワビを理解すればよい。」です。したがって、[6]の質問に答えるためには、松尾さんがワビを理解するかどうかがわかればよいことになります。,そこでProlog処理系は次に[4']のゴール(すなわち「理解する(松尾さん,ワビ)」)の実行を行います。,(規則1),一般に、あるゴール「G」を実行する時には「G」とユニファイ可能な頭部を持つ節「C」が探しだされ、「C」のゴール列が実行されます。ただし、ユニファイの際に「C」の頭部のある変数に項「T」が代入されたなら、「C」のゴール列に出現する同じ名前の変数にも、同じ項「T」が代入されなければいけません。,さて、[4']のゴールの実行を行うために、Prolog処理系は「理解する(松尾さん,ワビ)」とユニファイ可能な頭部を持つ節を上から順番に探索します。,そして[1]の節がみつけだされます。[4']のゴールの実行の目的は「松尾さんはワビを理解する。」かどうか判定することにありました。,一方[1]の節は「松尾さんはワビを理解する。」という意味ですから[4']のゴールは正しいことがわかります。,したがって[4']のゴールの実行は成功し、その結果[6]の質問も正しいことがわかります。,(規則2),一般に、あるゴール「G」を実行するときに「G」とユニファイ可能な頭部を持つ節「C」が探しだされ、しかも「C」がゴール列を持たなければ、「G」の実行は成功します。,では次に、変数を含む次の質問がどのように実行されるか考えてみましょう。,[7] | ?-理解する(松尾さん,X).,この場合もまず、[7]のゴールとユニファイ可能な頭部を持った節が上から順番に探しだされます。,最初に[1]が探しだされるでしょう。,このユニファイによって、[7]の「X」には「ワビ」が代入されます。,[1]はゴール列を持ちませんから、規則2により[7]のゴールは成功します。,そしてユニファイによって得られた情報から、「X」が「ワビ」であれば「松尾さんは“X”を理解する」が正しいことがわかります。,すなわち、質問のゴール列中に変数が出現する時、この変数にどんな項が代入されればゴールが正しくなるかはユニファイの過程で知ることができるのです。,尚、[7]の質問の場合、松尾さんが理解するものとして「ワビ」以外の答えが要求されたら、処理系は[7]のゴールとユニファイ可能な頭部を持つ別の節を探しに行きます。この場合、まず[2]の節が探しだされ、「松尾さんがサビを理解する。」ことがわかります。,4-3-3.バックトラック,Prologの実行の解説で使われた次のプログラムで、[8]のゴールはどのように実行されるか考えてみましょう。,[1] | 理解する(松尾さん,ワビ).↓,[2] | 理解する(松尾さん,サビ).↓,[3] | 理解する(ブリキ屋さん,サビ).↓,[4] | 理解する(X,風流):- 理解する(X,ワビ).↓,[5] | 理解する(X,風流):- 理解する(X,サビ).↓,  | ↓,[8] | ?-理解する(ブリキ屋さん,風流).,この場合もまず「理解する(ブリキ屋さん,風流)」とユニファイ可能な頭部を持つ節が探され[4]が最初に選びだされます。,このユニファイによって、[4]の「X」には「ブリキ屋さん」が代入されます。,したがって、次に実行すべきゴールは「理解する(ブリキ屋さん,ワビ)」になります。,ところが、これとユニファイ可能な頭部を持つ節は[1]~[5]の中に存在しませんから、このゴールは失敗します。,あるゴールの実行が失敗すると、処理系はバックトラック(後戻り)と呼ばれる作業をします。,この場合[8]のゴールとユニファイ可能な頭部を持つ[4]以外の節が探しに行かれます。,すると、今度は[5]の節がみつかり、さらに実行が続けられるのです。,[8]のゴールは、もともと[4]及び[5]の頭部とユニファイ可能でした。,しかし[4]のゴールと[5]のゴールを同時に実行することはできません。,そこで、まず[4]のゴールを実行してみて、失敗したら[5]のゴールを実行してみるというのがバックトラックなのです(ちょうどある人が道を歩いていると三叉路に出くわしてしまい、どちらに行ったらいいのかわからないので、まず左の方へ行ってみて、もし行き止まりならその三叉路まで戻って右の方へ行きなおすという状況に似ています)。,尚、バックトラックが行われる時には、失敗したゴールを実行する際に行われたユニファイはすべてキャンセルされます。例えば[8]のかわりにつぎの[8']のゴールが実行され、これが[4]の頭部とユニファイされたとします。,[8'] | ?-理解する(ブリキ屋さん,Y).,すると、このユニファイによって「Y」には「風流」が代入され[8']のゴールは,理解する(ブリキ屋さん,風流),となります。そして[4]のゴールはやはり失敗します。,ここでバックトラックが行われると、このユニファイの影響が帳消しにされて、再び[8']のゴールは「理解する(ブリキ屋さん,Y)」に戻りこのゴールの実行が続けられるのです。,このバックトラックとユニファイの機能のおかげで、通常の言語では解きにくい問題でも、Prologを使うと簡単に解ける場合がよくあるのです。,4-3-4.カット,バックトラックによって、Prolog処理系はゴールに他の解が無くなるまで試行錯誤をくり返します。,ところがこの試行錯誤は網羅的に行われますから、初めから失敗するとわかっているゴールを実行するために多くの時間をさく場合があります。,そういう場合、特別の述語「!」(カットと読みます。)を用いることによってバックトラックの制御を行うことができます。,例えば、次のプログラムを見てください。,これらは「ある遊園地に入場するために、子供は 500円,大人は 1,000円払う」という意味を持ちます。,[1] | 入場する(X,遊園地):-子供である(X),払う(X,ごひゃくえん).,[2] | 入場する(X,遊園地):-大人である(X),払う(X,せんえん).,つまり [1]の節は「“X”が遊園地に入場するためには“X”が子供であり、かつ“X”が 500円払えばよい」という意味ですし、[2]の節は「“X”が遊園地に入場するためには、“X”が大人であってかつ“X”が 1,000円払えばよい」という意味です。,さらに次のようなプログラムが続くとしましょう。,[3] | 子供である(タツヤ君).,[4] | 払う(タツヤ君,ひゃくえん).,[3]、[4]はそれぞれ「タツヤ君は子供です」及び「タツヤ君は100円払います」という意味を持ちます。そして、次のような質問を入力してみましょう。これは、「タツヤ君は遊園地に入場できるか?」という意味を持ちます。,[5] | ?-入場する(タツヤ君,遊園地).,この時、処理系はまず「入場する(タツヤ君,遊園地)」と単一化可能な頭部を持つ節を上から順に探し、[1] を見つけます。,単一化によって、[1] の「X」には「タツヤ君」が代入されますから、次には,子供である(タツヤ君),払う(タツヤ君,ごひゃくえん),というゴール列が実行されます。,このうち「子供である(タツヤ君)」は[3]によりに成功しますが「払う(タツヤ君,ごひゃくえん)」は成功しません。,したがって、バックトラックが起きて、処理系は[5]のゴールと単一化可能な頭部を持つ別の節を探しに行き[2]を見つけだします。,しかし、よく考えるてみるとタツヤ君は子供ですから[2]のゴールは成功するはずがありません。,つまり[1]の最初のゴール「子供である(タツヤ君)」が成功した段階で[2]の節を調べる価値はなくなっていたのです。,このことを処理系に教えてやるためには、[1]のプログラムを[1']のように書き直すといいでしょう。,[1'] | 入場する(X,遊園地):-子供である(X),!,払う(X,ごひゃくえん).,[1] との違いは、「子供である(X)」というゴールの次に 「!」が置かれたことにあります。,では、[1] を[1']で置き換えて、[5]の質問が行われると、処理系はこれをどのように実行するのでしょうか?,まず先程と同様に [1']の頭部と[5]のゴールを単一化して、,子供である(タツヤ君),!,払う(タツヤ君,ごひゃくえん),が実行されます。,次に「子供である(タツヤ君)」が成功するのも先程と全く同じです。,次のゴール「!」は、ただちに成功する述語です。,ただし、「!」が一旦成功すると、バックトラックによって 「!」が実行される以前の状態に戻る時には、[1']の頭部と単一化されたゴール(すなわち[5]のゴール)を強制的に失敗させます。,したがって、この時[5]のゴールと単一化可能な別の節があっても無視されます。,一般的に言うと、次のようになります。,(a)カットは実行されると直ちに成功します。,(b)カットが実行された以前の状態にバックトラックする時にはこのカットを含む節の頭部と単一化されていたゴールが、強制的に失敗させられます。,4-3-5.オペレータ,(A)オペレータの結合優先順位,ただ、「+(1,2)」を「1+2」と書けるようにしただけでは次の様な問題が出てきます。,それは例えば、「1+2*3」というふうに複数のオペレータを書いた場合に処理系が「(1+2)*3」と解釈したらいいか、「1+(2*3)」と解釈したらいいのか分らなくなってしまう事です。,算数のルールからは「1+ (2*3)」と解釈されなければなりません。,「1+ (2*3)」と解釈させるためには「+」より「*」の方が結合が優先される事を表さなければなりません。そこで考えられたのが「オペレータの結合優先順位」です。,オペレータの結合優先順位は、宣言する際に「1」から「1200」までの整数値で指定します。,この数が小さいほど結合優先順位が高く、逆に大きいほど結合優先順位が低くなります。,なお、オペレータの結合優先順位に関係なく「( )」で囲むとその中が優先されます。,また、「( )」が複数組ある場合はより内側が優先されます。,この、結びつきをどう解釈するかという問題は各オペレータの結合優先順位に差を付けてもまだ解決出来ない事があります。,それは、「同じ結合優先順位のオペレータが並んだ時にどう解釈するか」という問題が残っているからです。,そこでまた考えられたのが「オペレータの型」です。,「オペレータの型」はつまり、「左側の結びつきか、右側の結びつきかどちらを優先するか」という事を決定するものです。,つまり「1+2+3」を「(1+2) + 3」と解釈するのか「1+ (2+3)」と解釈するのかを判断する為のものです。,間置記法のオペレータの型には「xfy」「yfx」「xfx」があります。,ここで、「f」がファンクタをあらわし、「x」と「y」がそのアーギュメントを表わしていると考えるとよいでしょう。「x」と「y」の違いは次の点です。,アーギュメント「x」が表すアーギュメントの中で1番高い結合優先順位を持つオペレータ(カッコの中に出現するものは除く)が「f」で表されるオペレータの結合優先順位より低い。,「y」が表す中で1番大きい結合優先順位を持つオペレータが、「f」で表されるオペレータの結合優先順位より低いかまたは等しい。,例えば「+」の型を「xfy」に宣言したとすると「1+2+3」は「1+ (2+3)」と解釈されます。,逆に、「+」の型が「yfx」と宣言したとすると「1+2+3」は「(1+2)+3」と解釈されます。,もし、「+」の型が「xfx」と宣言すると、「+」の右にも左にも「+」と同じ結合優先順位を持つオペレータは置けません。したがって、「1+2+3」を1つの複合項として解釈することはできません。,また、引数が一つの複合項をオペレータ宣言する場合は、前置記法か後置記法かを決めなければなりません。,前置記法のオペレータは「fx」または「fy」という型があり、後置記法のオペレータは「xf」または「yf」という型があります。,(B)オペレータの宣言,オペレータの宣言は、標準組込述語の「op/3」を用いて行われます。,例えば、次のコマンドを入力すると「は」 というオペレータが宣言され、その大きさは「500」で、その型は「xfx」になります。,:-op(500,xfx,は).,つまり、「op」という述語の第1アーギュメントはオペレータの結合優先順位の大きさ、第2アーギュメントは型、そして、第3アーギュメントはオペレータの名前になります。,例えば、次の様にプログラムの最初にコマンドとして書いておけばいいでしょう。,:-op(500,xfx,は).,:-op(600,xf,を理解する).,(C)システムが準備しているオペレータ,Prologを起動した時に、既に定義されているオペレータがいくつかあります。,Prolog起動前に、次のようなオペレータ宣言がなされていると考えてください。,:-op(1200,xfx,:-).,:-op(1200,xfx,-->).,:-op(1200,fx,?-).,:-op(1200,fx,:-).,:-op(1150,fy,module).,:-op(1150,fy,help).,:-op(1150,fx,public).,:-op(1150,fx,mode).,:-op(1150,fx,index).,:-op(1150,fx,extern).,:-op(1150,fx,dynamic).,:-op(1150,fx,bltin).,:-op(1150,fx,###).,:-op(1100,xfy,;).,:-op(1050,xfy,->).,:-op(1000,xfy,',').,:-op(900,fy,spy).,:-op(900,fy,nospy).,:-op(900,fy,¥+).,:-op(700,xfx,is).,:-op(700,xfx,¥==).,:-op(700,xfx,¥=).,:-op(700,xfx,@>=).,:-op(700,xfx,@>).,:-op(700,xfx,@=,:-op(700,xfx,@,:-op(700,xfx,>=).,:-op(700,xfx,>).,:-op(700,xfx,=¥=).,:-op(700,xfx,==).,:-op(700,xfx,=,:-op(700,xfx,=:=).,:-op(700,xfx,=/=).,:-op(700,xfx,=..).,:-op(700,xfx,=).,:-op(700,xfx,,:-op(700,xfx,:=).,:-op(700,xfx,'/==').,:-op(700,xfx,#¥=).,:-op(700,xfx,#>=).,:-op(700,xfx,#>).,:-op(700,xfx,#=,:-op(700,xfx,#=).,:-op(700,xfx,#,:-op(580,xfy,::).,:-op(580,xfx,notin).,:-op(580,xfx,in).,:-op(560,yfx,..).,:-op(550,xfy,:).,:-op(540,xfy,#).,:-op(500,yfx,or).,:-op(500,yfx,and).,:-op(500,yfx,¥/).,:-op(500,yfx,'/¥').,:-op(500,yfx,-).,:-op(500,yfx,+).,:-op(400,yfx,rem).,:-op(400,yfx,mod).,:-op(400,yfx,>>).,:-op(400,yfx,,:-op(400,yfx,'//').,:-op(400,yfx,/).,:-op(400,yfx,*).,:-op(200,xfy,^).,:-op(200,xfx,'**').,:-op(200,fy,¥).,:-op(200,fy,-).,:-op(200,fy,+).,(D)オペレータ使用上の注意,(1) まず、次の2つの項を見比べてください。,(a)f(x,y),(b)f (x,y),明らかに(a)は「f」というファンクタと2つのアーギュメント「x」「y」を持つ複合項です。では(b)はどうでしょうか?,これは、「f」という前置記法のオペレータが1つのアーギュメント「(x,y)」を持つものとみなされます。したがって「複合項」で述べたような通常の記法で複合項を書き表す時には、ファンクタと左カッコの間に区切り記号(空白等)を入れてはいけません。,逆に、前置記法のオペレータのアーギュメントがカッコで囲まれている時には、オペレータとアーギュメントの間に区切り記号を入れる必要があります。,(2),複合項で述べたような通常の記法で、複合項を書き表す時に結合優先順位の大きさが1000以上のオペレータを持つ項をアーギュメントとして使う場合は、これをカッコで括ってください。,例えば、次の(c)は「assert」のアーギュメントの中に、結合優先順位の高さ1200のオペレータ「:-」 が出現しますから誤りです。(d)のように書き直してください。,(c)assert(理解する(X,風流):-理解する(X,ワビ)).,(d)assert((理解する(X,風流):-理解する(X,ワビ))).,(3),名前と記法が同じオペレータを2つ以上定義することはできません。,しかし、名前が同じでも記法が異なれば別のオペレータしとて定義することができます。また、一度定義されたオペレータは、名前と記法が同じ述語を「op」によって宣言すると再定義されます。,(4),前置記法のオペレータと同じ名前のアトムを使うと、そのアトムがオペレータと同じ結合優先順位を持ってしまいます。必要に応じて、このアトムをカッコで括ってください。,(5),オペレータとしての定義を解除したいときには、結合優先順位が0のオペレータとして再定義します。"}); htmllist.push({"file":"manuals/manual_program.html#program_4","title":"4-4.Prologの構文","text":"4-4.Prologの構文,4-4-1.トークン,プログラム言語の構文をBNF記法で表す場合、対応する構文木(ツリー構造)の末端(枝の先)に位置する記号はトークン(終端記号)と呼ばれます(BNF記法は「4-4-2.構文」参照)。Prolog言語の構文に現れるトークンには次のものがあります。,1.アトム,1.1,「'」(シングルクォート)以外の任意の文字と「''」(シングルクォート2つ) のみからなる文字列を「'」(シングルクォート)で囲んだもの。,1.2,英小文字または仮名漢字で始まる文字列で、英数字、仮名漢字及びアンダーラインのみからなるもの。,1.3,+ - * / ¥ ^ < > = `(バッククォート) : . ? @ # $ & のみからなる文字列で最初の2文字が/*でないもの。,1.4,; ! [] {}   のうちのどれか。,2.数字,2.1,0から9までの数字の列,2.2,最初1文字が0から9のうちのどれか、2番目が引用符号で、3番目以降に0から9までの数字の列が続くもの。ただし、最初の1文字が0のときには、a~f、A~F が混じってもよい。,3.変数,3.1,アンダーラインで始まり、英数字、仮名漢字及びアンダーラインのみよりなる文字列。,3.2,英大文字で始まり、英数字、仮名漢字及びアンダーラインのみよりなる文字列。,4.ストリング, ,「”」以外の任意の文字と「””」のみからなる文字(長さ0でもよい。)を「””」で囲んだもの。,5.句点文字, ,( )[ ]{ }, の各文字。,6.コメント,6.1,「/*」と「*/」に囲まれた文字列で、「*/」を含まないもの。,6.2,「%」で始まり行末で終わる任意の文字列。,7.終止符, ,長さ2の文字列で、1文字目がピリオド、2文字目の文字コードが32以下のもの。,4-4-2.構文,以下に、トークンからPrologのプログラムを構成するための規則をBNF記法を用いて示します。,★BNF記法とは・・・,例えば、,<文>::=<節>|<コマンド>|<質問>,は「<文>とは、<節>か<コマンド>かあるいは<質問>である」という意味です。,つまり、「::=」の左辺が何であるのかを右辺が説明しているのです。,そして、右辺の「|」は「または」という意味を持ちます。,考えようによっては、「::=」はPrologの「:-」に対応し、「|」は「;」に対応するとみることもできます。,<文>や<節>のように「<」と「>」で囲まれた文字列は、それがどのようなものか説明されなければいけないものです。,従って、「<節>」は、単なる長さ3の文字列ではなく、どこかで定義される何かを表します。,一方次のように,<コマンド>::=:-<ゴール列><終止符>,の中に出てくる「:-」のように「<」と「>」で囲まれていない文字列は、単にその文字列を表します。,先程定義した各トークンは<アトム>、<数字>、<変数>、<ストリング>、<終止符>という形でBNF記法の中に出現します。,コメントはインタプリタに無視されますので、これは省略しました。,また、句点文字は<句点文字>という形でなく、個々の文字( ) [ ] { } , ・・の形で出現します。,結局Prologのプログラムとは、ここで定義される<文>の列です。,★Prologプログラム構成,<文>::=<節>|<コマンド>|<質問>,<コマンド>::=:-<ゴール列><終止符>,<質問>::=?-<ゴール列><終止符>,<節>::=<単位節>|<非単位節>,<単位節>::=<頭部><終止符>,<非単位節>::=<頭部>:-<ゴール列><終止符>,<頭部>::=<項>,{ただしこの<項>は<整数>,<実数>,<変数>ではない},<ゴール列>::=<ゴール>,|<ゴール>, <ゴール列>,|<ゴール>; <ゴール列>,<ゴール>::=<項>,{ただし、この<項>は<整数>,<実数>ではない},<項>::=<部分項(1200)>,<部分項(N)>::=<項(M)> {ただしM≦N},<項(N)>::=<オペレータ(N,fx)>,|<オペレータ(N,fy)>,|<オペレータ(N,fx)> <部分項(N-1)> (注1),|<オペレータ(N,fy)> <部分項(N)>    (注1),|<部分項(N-1)><オペレータ(N,xfx)><部分項(N-1)>,|<部分項(N-1 )><オペレータ(N,xfy)><部分項(N)>,|<部分項(N)><オペレータ(N,yfx )><部分項(N-1 )>,|<部分項(N-1 )><オペレータ(N,xf)>,|<部分項(N)><オペレータ(N,yf)>,<項(1000)>::=<部分項(999)>,<部分項(1000)>,<項(0)>::=<ファンクタ>(<アーギュメント列>)   (注2),|(<部分項(1200)>),|{<部分項(1200)>},|<リスト>,|<ストリング>,|<定数>,|<変数>,<オペレータ(N,T)>::=<ファンクタ>,{ただし、この<ファンクタ>は型T,結合の強さNで宣言されたもの},<アーギュメント列>::=<部分項(999)>,<アーギュメント列>,|<部分項(999)>,(注1) ただし<部分項(N-1)>や<部分項(N)>がカッコでくくられている時には、<オペレータ(N,fx)>や<オペレータ(N,fy)>との間に区切り記号が必要。,(注2) <ファンクタ>と左カッコ '('の間には空白等の記号を入れてはいけません。,<リスト>::=[ ]|[<リストアーギュメント>],<リストアーギュメント>::=<部分項(999)>, <リストアーギュメント>,|<部分項(999)>・・<部分項(999)>,|<部分項(999)>,<定数>::=<アトム>|<整数>|<実数>,<整数>::=<数字>|-<数字>,<実数>::=<数字>.<数字>,|-<数字>.<数字>,|<数字>.<数字>e<整数>,|-<数字>.<数字>e<整数>,<ファンクタ>::=<アトム>"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter","title":"5-1.概要","text":"5-1. 概要,インタプリタはPrologのコードを逐次解釈しながら実行する処理系です。,一括翻訳するコンパイラに比べて処理速度は落ちますが、ソースプログラムをそのままヒープ領域(プログラム領域)に読み込むだけで即実行でき、実行の中断、任意の時点でトレース(述語毎に述語名や引数の値を表示しながらの実行)などができるため、プログラムの開発段階でよく用いられます。,AZ-Prologが提供するインタプリタには以下の3種類があります。,(1).ウインドウアプリケーションインタプリタ,(2).コンソールアプリケーションインタプリタ,(3).CGIインタプリタ,最初の2つはユーザが直接コマンドを実行して利用しますが、3つ目はその名の通りPrologで書かれたCGIプログラムを解釈実行するためのもので、WEBサーバ(HTTPサーバ)によって起動されます。,(1).ウインドウアプリケーションインタプリタ(標準),prolog.exe(Linux版またはMac版ではprolog)を起動します。,Windows版ではインストール時にスタートメニューにAZ-Prologが追加されますが、起動されるのはこのインタプリタです。,トップレベル(この語句については5-2参照)は、,|?-,となります。ここからプログラムを読み込んだり、実行したりすることができます。バックスペースキー2度押しで"?-"を消せば、prolog_c(.exe)と同様、ここからプログラム(節)を入力することもできます。,内蔵エディタ(9-11参照)、キーバッファ機能(5-6-2.リストア参照)および任意の場所へのカーソル移動(9-11-3.AzEditのカスタマイズ参照)などの関連述語が利用できます。,(2).コンソールアプリケーションインタプリタ,prolog_c.exe(Linux版またはMac版ではprolog_c)を起動します。トップレベルは,|,となります。ここからプログラム(節)を入力することもできますし、入力を「?-」から始めれば、prolog(.exe)と同様、プログラムを実行することができます。,内蔵エディタ、キーバッファ機能およ関連述語は利用できませんが、コンソールのコマンドラインで他のコマンドとパイプでつなげたり、出力をリダイレクトしたりして利用することもできます。以下はその例です。,<例:Windows>,C:¥>echo ?-['queen.pl'],q(5),halt. | prolog_c -nologo > tmp,<例:LinuxまたはMac版>,$ echo "?-['queen.pl'],q(5),halt." | prolog_c -nologo > tmp,となります。ここからプログラム(節)を入力することもできますし、入力を「?-」から始めれば、prolog(.exe)と同様、プログラムを実行することができます。,(3).CGIインタプリタ,prologcgi.exe(Linux版またはMac版はprologcgi),このインタプリタを起動するのは、ユーザ入力によるコマンド実行ではなく、WEBサーバ(HTTPサーバ)です。,色々なサーバが存在しますが、本マニュアルでは、Apacheを前提として説明しています。,cgi-binなどの下におかれた所定の形式(これについては「9-4.CGIインターフェースとユーティリティ」を参照してください)のPrologプログラムの先頭にこのインタプリタを指定することで、ユーザがブラウザからHTTPリクエストを送るとWEBサーバからProlog(CGI)プログラムが呼ばれ、その時に起動されます。,CGIインタプリタへのパスが通っているか、apache¥binの下にCGIインタプリタがおかれていれば、CGIファイルの先頭に次の書式でインタプリタを指定します。,ファイル先頭の記述<例>,#! prologcgi,フルパスで記述することで任意のバージョン(あれば)のCGIインタプリタを起動することができます。,ファイル先頭の記述<例>,#! C:¥AZ-Prolog.800x64¥bin¥prologcgi,CGIの書き方は、以下の場所にサンプルがありますのでご参照ください。,Windows版,:%AZProlog%¥sample¥cgi_demo,Linux版,:${AZProlog}/share/azprolog/sample/cgi_demo,Mac版,:${AZProlog}/share/azprolog/sample/cgi_demo"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_2","title":"5-2.トップレベル","text":"5-2.トップレベル,トップレベルとは、インタプリタ立上げ直後にプロンプト(入力促進記号)が出て入力待ちになっている状態を指します。,通常、この状態でPrologの質問(ゴール列)を入力します。,5-2-1.タイプ入力,(1).ヒストリ・テンプレート機能,AZ-Prologでは、トップレベルでの入力の手間を軽減する為、過去に入力・実行した履歴を文字列(改行除く)として10行分まで記憶しています。,そして各種コマンド(コントロールキーと特定のアルファベットキーを同時に押す)操作により、その入力履歴を表示したり、その中からある文字列を選んで呼出し、更にその文字列に対して一文字削除・挿入などの編集も出来ます。これらを総称してヒストリ・テンプレート機能と呼びます。,では、そのオペレーションを例を挙げて説明しましょう。,過去に,| ?-a(1).,:,| ?-b(1).,:,| ?-a(2).,:,| ?-b(2).,:,| ?-a(3).,:,| ?-b(3).,:,| ?-a(4).,:,| ?-b(4).,:,| ?-a(5).,:,| ?-b(5).,などの文字列(質問)を入力していたとします。,ここで「CTRL-X」を入力すると…,| ?-^X HISTORY 1: ?-b(5). 2: ?-a(5). 3: ?-b(4). 4: ?-a(4). 5: ?-b(3). 6: ?-a(3). 7: ?-b(2). 8: ?-a(2). 9: ?-b(1).10: ?-a(1).,と表示されます。,このように最後に入力された行の文字列から順に表示されます。,入力履歴を遡って直前の入力文字列を呼出したい場合は、「CTRL-U」を1回入力します。続けて「CTRL-U」を入力すると、更に前の文字列が順々に呼び出されます。また「CTRL-N」で逆順にも呼出せます。,| ?-b(5).^U ↓| ?-a(5).^U ↓| ?-b(4).^U : :,と表示され、再度入力したい文字列が表れたら「Enterキー」を押します。,するとその文字列をタイプ入力されたのと同様の動作をします。,「CTRL-U」によって呼び出された文字列は「テンプレートバッファ」と呼ばれるところにも転送されます。,このテンプレートバッファには通常、最後に入力・実行した文字列がセットされますが、「CTRL-U」を押すと、その時呼び出された文字列に置き換わります。,文字列を入力して実行する(Enterキーを押す)前でも、「CTRL-T」でテンプレートバッファにコピーできます。このコマンドは、長い文字列を入力した後で間違いを見つけた時など、実行する前に修正したい場合に使えます。,「CTRL-U」、「CTRL-N」、「CTRL-T」を押した直後は、テンプレートバッファの内容は既に入力行にも現れています。これを編集したい場合は、残念ながらカーソルを修正したい場所に移動して直すことはできないので、バックスペースキーで修正位置までを消すか、「CTRL-Q」を押して一旦全てをクリアします。,「CTRL-Q」を押すと「?-」まで消えてしまいますが、この状態はヒープ領域への節の入力が可能(但し1行のみ)な状態で、質問を入力するには「?-」から始めることになります。でも後述の「CTRL-F」や「CTRL-A」でテンプレートバッファの内容を呼び出すと「?-」から始まるので、安心してください。,では、一旦「CTRL-Q」で入力をクリアして、続いて「CTRL-A」を押してみましょう。「CTRL-A」は現在のテンプレートバッファの内容をトップレベルの入力行にコピーするコマンドです。,テンプレートバッファの内容が「b(5).」であるとすると…,| ?-b(5).,が再び現れるはずです。,バックスペースキーで「?-」の後ろを全て消して、テンプレートバッファの内容を一文字ずつトップレベルにコピーする「CTRL-Fコマンド」を使うと、,| ?-^F ↓,となります。これを使うと内容の一部を書換える事ができます。,例えば、「b(5).」の引数を「Ⅹ」にしたい場合は…,| ?-^F ↓| ?-b^F ↓| ?-b(X  ,また、「b(5).」の述語名を「c」に変更したい場合は…,| ?-c  , ↓,| ?-c^A , ↓,| ?-c(5).,1文字をスキップする「CTRL-Eコマンド」を使うと、例えばテンプレートバッファの内容が「a(X,Y).」の時に、ここから2文字削った「a(X).」という文字列を現在の行にコピーできます。,| ?-^F, ↓,| ?-a^F, ↓,| ?-a(^F, ↓,| ?-a(X^E^E , ↓,| ?-a(X^A, ↓,| ?-a(X).,これとは逆にテンプレートの文字列の途中に新たな文字列を挿入する事も出来ます(挿入モードにする「CTRL-Wコマンド」)。,例えばテンプレートバッファの内容が「a(X).」の時に「a(X,Y).」という文字列を現在の行にコピーしてみましょう。,| ?-^F,↓,| ?-a^F,↓,| ?-a(^F,↓,| ?-a(X^W,↓,| ?-a(X,Y,↓,| ?-a(X,Y^A,↓,| ?-a(X,Y).,のようにできます。,以下はヒストリ・テンプレートコマンド一覧です。,CTRL-X,ヒストリーの表示。,CTRL-F,入力行にテンプレートバッファから1文字コピーする 。,CTRL-A,入力行にテンプレートバッファに残っている全ての文字をコピーする。,CTRL-E,テンプレートバッファ内の1文字をスキップする。,CTRL-W,挿入モードに入る。もう1度押すと挿入モードを解除する。,CTRL-T,入力行の内容をテンプレートにコピーする。,CTRL-Q,入力行をクリアする([?-」も消される)。,CTRL-U,一つ前の履歴で入力行を置き換える。同時にテンプレートバッファにもコピーする。,CTRL-N,一つ後の履歴で入力行を置き換える。同時にテンプレートバッファにもコピーする。,5-2-2.シェルエスケープ・外部プログラムの実行,AZ-Prologでは処理系内からOSコマンドを実行出来ます。,そのためにOSコマンドを一つだけを実行する「system/1」述語と、一旦OSのコマンドレベルに抜けてしまう「sh/0」述語の2つの標準組込述語があります。,例えば、カレントディレクトリのファイル名を確認するには次の様にします(以下はWindows版DOSコマンドの例です。Linux版またはMac版の場合は"ls"に置き換えてください。但し、lsコマンドの出力は述語呼び出しの直下には表示されません。次に説明するshを実行して、Prologを起動したシェル画面に戻ると出力を確認することができます。),| ?-system("dir/W").↓, :,:, :,yes,| ?-,また、一旦OSのコマンドレベルに抜けるには…,| ?-sh.,Microsoft Windows [Version x.x.xxxx],Copyright (c) 20XX Microsoft Corporation. All rights reserved.,C:¥>dir,:,:,:,C:¥>exit,yes,| ?-,とします。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_3","title":"5-3.プログラムの入カ方法","text":"5-3.プログラムの入カ方法,プログラムを入力するには以下のような4つの方法があります。,ファイルからインタプリタ(ヒープ領域)に直接読み込む。,コンソールから直接インタプリタに入力する。,ファイルから内蔵エディタAzEditに読み込んだ後、AzEditからインタプリタにプログラムを読み込ませる。,AzEditでコンソールから入力した後、AzEditからインタプリタにプログラムを読み込ませる。,プログラムをコンソールから入力する場合、およびエディットする場合にはAzEditを使うと効率よく入力できます。 また、ファイルからプログラムを読み込む場合にも一度AzEditを介して読み込んだ方がプログラムリストの参照・プログラムの変更などのときに便利です(本節においては上記のうち1.および2.についてのみ説明します。AzEditの使用方法については「9-11.内蔵エディタ(AzEdit)」を参照してください。なお、Prologの文法については、「4.Prolog言語」において解説されています。),5-3-1.コンソールからのプログラム入カ,プログラムはコンソール(端末)で直接入力することができます。,コンソールからプログラムを入力するには次の2通りの方法があります。,インタプリタのトップレベルにおいて「CTRL-H(またはBS KEY、Mac版の場合はdelete KEY)」を2回押すと「?-」が消え、カーソルも2文字分戻ります。この状態でプログラムを入力することができます。但し、この場合は1行限りです。,| ?-^H,↓,| ?^H,↓,| my_append([],X,X).↓,↓,| ?-^H,↓,| ?^H,↓,| my_append([A|X],Y,[A|Z]):-my_append(X,Y,Z).↓,↓,| ?-listing.↓     ,my_append([],X,X).,my_append([A|X],Y,[A|Z]) :-,my_append(X,Y,Z).,yes,| ?-,数行をまとめて入力するには…,| ?-[user].,この後に入力するとインタプリタは、節あるいは指令の入力を待つ状態となります。,インタプリタのトップレベルに戻る場合は「END_OF_INPUT」文字(WindowsはCTRL-Z、LinuxまたはMacはCTRL-D)を入力してください。,この方法で上と同じプログラムを入力してみましょう。下の例はWindows版の場合です。Linux版またはMac版でCTRL-Zを入力すると、インタプリタのプロセスがサスペンド(停止)してしまうので注意してください。,もしうっかり入力して、シェルの画面が表示された時は、fgコマンドを実行してください。元に戻れます。,| ?-[user].↓,| my_append([],X,X).↓,| my_append([A|X],Y,[A|Z]):-my_append(X,Y,Z).↓,| ^Z   ,yes,| ?-listing.↓,my_append([],X,X).,my_append([A|X],Y,[A|Z]) :-,my_append(X,Y,Z).,yes,| ?-,この様に同じ結果に成る事が分ります。,(注),プログラムをコンソール(端末)からインタプリタに直接入力するのは、その節が永久に必要でないか、または数ステップのプログラムを入力する場合以外はおすすめできません。,プログラムの有効利用のため、プログラムのテキストを含むファイルをエディタで作成して使用することをおすすめします。,5-3-2.ファイルからのプログラム入カ,(1).コンサルト,Prologプログラムをファイルから読み込む事を「コンサルト(consult)」といいます。,コンサル卜するにはインタプリタのトップレベルにおいて次のように入力します。,| ?-consult('パス名¥ファイル名').↓,または、省略記法で、,| ?-['パス名¥ファイル名'].↓,パス名を省略したときにはカレントディレクトリから読み込みます。,<例>カレントディレクトリのski.plというファイルからプログラムを読み込む。,| ?-['ski.pl'].↓,カレントディレクトリの下のplというディレクトリからlist.plというファイルからプログラムを読み込む。,| ?-['pl¥lisp.pl'].↓,プログラム入力が正常に終わると、コンソールに「yes」およびプロンプトが表示されます。,インタプリタを起動してから初めてあるプログラムを読み込む場合には以上の方法で十分です。,しかし、そうではない場合には不都合なことが起こる場合があります。,と言うのは、コンサルトは以前に読み込んだプログラムがあっても、それらを消去してから新たに読み込むと言うことをしません。つまり、古いプログラムはそのまま残り、それに新しいプログラムが付け加えられます。従って、運が悪いと古いプログラムと新しいプログラムがごちゃまぜになって正常に動かなくなる事もあります(以下の例)。,<例>,| ?-s_new.↓,yes,| ?-['my_append.pl'].↓,yes,| ?-listing.↓,my_append([],X,X).,my_append([A|X],Y,[A|Z]) :-,my_append(X,Y,Z).,yes,| ?-['my_append.pl'].↓,yes,| ?-listing.↓,my_append([],X,X).,my_append([A|X],Y,[A|Z]) :-,my_append(X,Y,Z).,my_append([],X,X).,my_append([A|X],Y,[A|Z]) :-,my_append(X,Y,Z).,yes,| ?-,「ここで、「s_new/0」はすべてのプログラム(ユーザ定義の節)を消去する述語です。また「listing/0」はプログラムを出力する述語です。,最初に「s_new/0」でプログラムを消去した後、同じファイルを2度続けて「 consult 」した結果、「my_append/3」の定義が2重になっているのがわかります。(もちろん、これは使い方が悪いのであって「 consult 」の欠点ではありません。このような性質を利用してプログラムを複数のファイルに分けておくというようなこともできます。),consultによる述語の多重定義や、新旧定義の混在を避ける方法として、次の2つがあります。,ひとつは、上の「s_new/0」述語を実行してプログラムをすべて消去してから「 consult 」するという方法です。,もうひとつは、次に述べる「リコンサルト(reconsult)」する方法です。,(2).リコンサルト,古い述語定義を新しい定義で上書きするようにしてファイルから読み込むことを「リコンサルト(reconsult)と言います。,リコンサル卜するにはインタプリタのトップレベルでは次のように入力します。,| ?-reconsult('my_append.pl').↓,または、省略記法で,| ?-[-'my_append.pl'].↓,このようにファイル名のまえに「-」を付けると、そのファイルを「 reconsult 」します。,「 reconsult 」すると指定されたファイルの中で定義されている述語が既にインタプリタの中に存在していた場合には、それらを消去してファイル中の定義に置き替えます。したがって上のような事は起こりません。,これらをプログラム中に書いておく事もできますから、ソースファイルをいくつかに分割しておき、必要に応じて次々と読み込んでいく事もできます。,しかしこの方法では処理速度が落ちますので、プログラム領域の十分大きいAZ-Prologではあまり賢明な方法とは言えません。実行途中にレスポンスを悪くするより、最初に全て読み込んでおくことをお勧めします。,<補足1>,コンサルトとリコンサルトでは、DCGトランスレータが内蔵され、読み込みの際ファイル中のDCG記法の節をPrologの節に変換しHeapに登録します。,<例>,< ファイル中のDCG記法の節 >, ,< Heapに登録される節 >,vp([vp,Vt,Np])-->vt(Vt),np(Np).,<変換>,vp([vp,Vt,Np],_2,_3):-vt(Vt,_2,_4),np(Np,_4,_3).,n([n,cat])-->[cat].,<変換>,n([n,cat],[cat|_0],_0).,<補足2>,Prolog起動時のプログラムファイル読み込みは、「3-3-2.起動時に読み込むプログラムファイルの指定」をご参照ください。,【注意】,UTF-8の文字コードプログラムファイルを作成する場合、BOM(バイトオーダーマーク)を付けないでください。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_4","title":"5-4.プログラムの起動","text":"5-4.プログラムの起動,5-4-1.質問による起動,Prologではインタプリタに「質問」を発することによってプログラムの実行が始まります。,また、Prologプログラムに書かれている情報を使って、その質問が正しいかどうかを判定する作業をPrologプログラムの「実行」といいます。,<例>ソースファイル('RIKAI.PL')が次の内容であり、カレントディレクトリにある時・・・,理解する(松尾さん,ワビ).,理解する(松尾さん,サビ).,理解する(ブリキ屋さん,サビ).,理解する(X,風流):- 理解する(X,ワビ).,理解する(X,風流):- 理解する(X,サビ).,(注:このファイルはサンプルプログラムには含まれていません。),| ?-['RIKAI.PL'].↓ /*ファイル'RIKAI.PL'からプログラムを読み込む*/,yes,| ?-listing.↓ /*プログラムのリスト*/,理解する(松尾さん,ワビ). /*松尾さんは“ワビ”がわかる。*/,理解する(松尾さん,サビ). /*松尾さんは“サビ”がわかる。*/,理解する(ブリキ屋さん,サビ). /*ブリキ屋さんは“サビ”がわかる。*/,理解する(X,風流) :-,理解する(X,ワビ). /*“ワビ”がわかる人は風流を理解する。*/,理解する(X,風流) :-,理解する(X,サビ). /*“サビ”がわかる人は風流を理解する。*/,yes,| ?-理解する(松尾さん,ワビ).↓ /*松尾さんは“ワビ”がわかるか?*/,yes,| ?-理解する(ブリキ屋さん,サビ).↓ /*ブリキ屋さんは“サビ”がわかるか?*/,yes,| ?-理解する(ブリキ屋さん,ワビ).↓ /*ブリキ屋さんは“ワビ”がわかるか?*/,no,| ?-理解する(ブリキ屋さん,風流).↓ /*ブリキ屋さんは風流を理解するか?*/,yes,| ?-,このように、インタプリタは質問に対して、それがプログラムから事実かどうかを答えます。,ここでは、プロンプト(?-)に続く「理解する(松尾さん,ワビ)」や「理解する(ブリキ屋さん,サビ)」(これらをゴールと呼びます)が正しいかどうかをインタプリタが判定したわけです。(インタプリタがどのように判定するのかについては「4-3.プログラムの実行」で説明しています。),あるゴールが正しいということが言えた場合、そのゴールの実行に成功したといいます。逆に、正しいと言えなかった場合には失敗したといいます。,ところで、上の質問はどれも変数を含んでいませんでした。次に変数を含む質問をしてみます。(英大文字は変数を表します。変数についての詳細は「4-1-2.変数」を参照してください。),| ?-理解する(松尾さん,X).↓ /*松尾さんは何を理解しているか?*/,X = ワビ↓ /*それはワビです。*/,yes,| ?-,質問が変数を含む場合には、このようにその変数に何を代入したときに質問が正しくなるかを表示します。ここで「X=ワビ」のところで「↓」を入力したのは、この答えでユーザが満足したからです。これ以外の解をみつけたいときには「;↓」(セミコロン)を入力します。,| ?-理解する(松尾さん,X).↓ /*松尾さんは何を理解しているか?*/,X = ワビ;↓ /*他の解を探せ。*/,X = サビ;↓ /*他の解を探せ。*/,X = 風流;↓ /*他の解を探せ。*/,X = 風流;↓ /*他の解を探せ。*/,no,| ?-,もうこれ以上別の解がないときには、このように「no」を表示します。,<変数が2個以上ある場合の例>,| ?-理解する(X,Y).↓,X = 松尾さん,,Y = ワビ↓,yes,| ?-,これまでの例では、質問がただ一つのゴールのみから成っていました。,質問としていくつものゴールを書き連ねることもできます。,| ?-理解する(X,ワビ),理解する(X,サビ).↓ /*“ワビ”も“サビ”も理解しているのは誰か?*/,X = 松尾さん;↓ /*他の解を探せ。*/,no,| ?-,5-4-2.コマンドによる起動,質問の他に、プログラムを起動するものとしてコマンドがあります。コマンドを入力する場合には、インタプリタのコマンドレベルにおいてCTRL-H (またはBS KEY)を2回押して「?-」を消し、その代わりに「:-」と打ちなおしてから質問の時と同じように実行したいゴールを書き並べてください。,| :-['ski.pl'].↓,| ?-,質問とは異なり、コマンドの実行に成功した場合には何も表示されません。変数が含まれている場合にも、別の解を探すようなことはしません。,ただし、失敗した場合には「?」が表示されます。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_5","title":"5-5. 実行の中断・出力コントロール","text":"5-5. 実行の中断・出力コントロール,プログラムの実行をストップさせたり、表示を一時的に止めておきたい時があります。,この節では、AZ-Prologのそのような機能について解説します。,5-5-1.インタプリタの実行の中断(ブレークレベル),インタプリタが働いているときに「INTERRUPTキー」(CTRL-C)を押す事によって実行を中断させることができます。,(下の例は、無限ループのプログラムです。),| ?-repeat,fail.↓,INTERRUPT ,Interrupting A(bort),B(reak),C(ontinue) or O(s level) ?a↓,| ?-,この時以下のようなコマンドが使えます(上の例では“A(bort)”コマンドを使っています)。,A(bort),実行を中止しインタプリタはトップレベルにまで戻ります。,標準組込述語の「abort/0」を実行した場合とまったく同じです。,「errorset/2 」による実行の場合には、そのerrorsetによってトラップされます。,B(reak),実行を保留して、ブレークレベル(後述)を一つ深くします。,標準組込述語の「break/0」を実行した場合とまったく同じです。,C(ontinue),そのまま実行を続けます。,O(s),Prologインタプリタから、コマンドプロセッサヘ一時的に制御を移します。EXITコマンドを実行することによって、Prologの実行を再開できます。,標準組込述語の「sh/0」を実行した場合とまったく同じです。,T(race),このコマンドは、デバッグモードの場合のみ有効です。,トレースを始めます。,標準組込述語の「trace/0」を実行した場合と同じです。,「6.デバッカ」参照してください。,ブレークレベル,Bコマンドでブレークをかけると、一見インタプリタのトップレベルに戻ったように「?-」のプロンプトが出て質問(コマンド)待ちの状態になります。しかし、実際にはそれまで実行されていたプログラムは凍結状態で、すべての情報はそのまま保存されています。この状態をブレークレベルといいます。,あるブレークレベルで他のプログラムを実行中に再び別のブレークをかけることもできます。つまりブレークレベルは多階層に成り得る訳で、この階層の深さもブレークレベルと呼び、数字で表します。ブレークした場合にプロンプトの上の行に表示される鍵カッコで囲まれた数字は、その意味のブレークレベルです。,標準組込述語の「break/0」によって実行を中断した場合とまったく同じ状態になります。,また「unbreak/0」によって実行の再開ができます。,★デバッグモードで実行していた場合でも、break時に起動されるインタプリタのモードはノーマルモードで始まります。,以下の例ではデバッグモードから始まっています。プロンプトの変化に注目してください。デバッグモードでは「||?-」、ノーマルモードでは「|?-」となっています。デバッグモードでの割り込み(INTERRUPT)時のコマンド要求行ではTraceコマンドが増えていることも確認できます。,<例>,||?-repeat,write(a),fail.↓,aaaaaaaaaaaaaaaaaaa INTERRUPT,Interrupting A(bort),B(reak),C(ontinue),T(race) or O(s level) ?b↓,debug mode off,[1],| ?-repeat,write(b),fail.↓,bbbbbbbbbbbbbbbbbbb INTERRUPT,Interrupting A(bort),B(reak),C(ontinue) or O(s level) ?b↓,[2],| ?-true.↓,yes,[2],| ?-unbreak.↓,bbbbbbbbbbbbbbbbbbb INTERRUPT,Interrupting A(bort),B(reak),C(ontinue) or O(s level) ?a↓,[1],| ?-unbreak.↓,aaaaaaaaaaaaaaaaaaa INTERRUPT,Interrupting A(bort),B(reak),C(ontinue),T(race) or O(s level) ?a↓,LOOP = xxxxx,||?-,5-5-2.コンソール出カコントロール,キーボードからコントロールコードを入力することによって、コンソールに対する出力を制御することができます。,CTRL-S,コンソールに対する出力を保留します。したがって、インタプリタの実行も一時ストップします。,この状態においてINTERRUPTキーを押しても前項の場合(いきなりINTERRUPTキーを押した場合)と同じコマンド要求メッセージが出力されます。,CTRL-Q,CTRL-Sによって保留されていたコンソールに対する出力を再開します。,<例>,|| ?-repeat,write(a),fail.↓,aaaaaaaaaaaaaaaaaaa INTERRUPT,Interrupting A(bort),B(reak),C(ontinue),T(race) or O(s level) ?,ここでも、前項の場合(いきなりINTERRUPTキーを押した場合)と同じコマンド要求メッセージが出力されて同じコマンドが使えます。,5-5-3.ストリームヘの入出力,このマニュアルでは、ファイルやコンソール画面、プリンタなどの装置との入出力を統一的に扱うための抽象的な対象を「ストリーム」と呼んでいます。コンソールやプリンタなどの装置もディスク上のファイルと同等に扱うよう特別のファイル名が与えられています。,このストリームへの入出力方法には、次の二通りがあります。,カレントストリームへの入出力,予めカレントのストリームを切り換え、個々の入出力の際にはストリームの指定をしない方法。,ストリーム指定の入出力,ファイルオープン時にストリームを取得し、個々の入出力に際してはその都度明示的にストリームを指定する方法。,(1).カレントストリームヘの入出力,あらかじめ入出力対象ファイルを指定してカレントストリームを切換えておき、その暗黙のストリームに対して入出力する方法を説明します。,まず、「see/1」「tell/1」「tella/1」等の組込述語で、入出力の対象となるファイルのパス名を引数として指定します。これにより、そのファイルが入出力対象(カレントストリーム)となります。この時、指定されたファイルがまだオープンされていなかった場合は、オープンしてからカレントストリームを切換えます。,カレントストリームを「seen/0」「told/0」という組込述語によってクローズすると、カレント値は一つ前のストリームに切り換えられます。ただし、カレントストリームの既定値(起動時)は、入出力共コンソールです。,したがって、インタプリタ立上げ後一度もストリームが切換えられてないとコンソールに対して入出力がなされます。,★パス名の与え方,ファイルのパス名は、その文字列をシングルクォート「'」で囲ったアトムで指定します。ただし、そのままでアトムとして認められるパス名(ディレクトリ階層の区切り記号¥や/、あるいはピリオド「.」が含まれない、例えばカレントディレクトリにある拡張子なしのファイル名や特殊ファイル名等)の場合には、特にシングルクォート「'」で囲む必要はありません。,例えば「 azedit.pl 」というファイルを現在の入力ストリームとする場合は、,| ?-see('azedit.pl').,を実行すればよい事になります。,この場合は、カレントディレクトリにある「 azedit.pl 」というファイルが現在の入力ストリームになります。,また、Windows版ではドライブ名を明示的に指定する事もできます。その場合にはドライブ名をパス名に含める事も出来ます。,例えば、,| ?-consult('b:queen.pl').,のように指定します。,この場合はBドライブにある「 queen.pl 」というファイルがconsultされます。但し、queen.plはBドライブのカレントディレクトリにあると言う前提です。,★特殊ファイル,入出力をファイルという概念で統一的に扱うために以下のような4個の特別なファイルが用意されています。,パス名,装置名,con,コンソール(キーボードとディスプレイ)。END_OF_INPUTキーで入力終了,user,同上,nul,入力ファイルとしては空のファイル(ダミーファイル)。,結果的にはここに出力しても何もしなかったのと同じ。,edit,現在のエディタバッファ,★ファイルエラーモード,その他の機能として、入出力関係の述語がエラーを起こした場合、通常は実行を中断しますが、ただ単に失敗するようにする事もできます。,どちらのモードにするかを「fileerrors/2」という述語によって切り換えることができます。,(2).ストリーム指定の入出力,前項で説明した現在のストリームに入出力する方法では、入出力先をそれぞれ一つしか同時にオープンする事が出来ません。,AZ-Prologでは、ストリームに識別値(ストリーム値)を付けてダイレクトに指定して入出力できる組込述語があります。,ここではその概略を説明します。,まず、ストリームの指定はそれを識別する為のストリーム値という特別の項(Prologのデータ)を使います。,この値をストリーム指定入出力述語(「read/2」「get0/2」「get0/2」「listing/2」「write/2」「writeq/2」「put/2」「seek/2」)の引数で指定すると、カレント入出力ストリームを切換える事なしに(無関係に)指定されたストリームに対して入出力できます。,ストリーム値は、具体的にはファイルオープン述語(「see/2」「tell/2」「tella/2」)によってファイルを入出力オープンすると、それらの述語の第2引数に返される値です。,なお、これらの述語によってオープンされたファイルは、入出力完了後には必ず対応するファイルクローズ述語(「seen/1」「told/1」)でクローズしなければなりません。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_6","title":"5-6.ヒープ領域の保存","text":"5-6.ヒープ領域の保存,プログラム領域をAZ-Prologでは「ヒープ領域」と呼んでいます。,ヒープ領域では、プログラムは処理しやすいように中間言語で格納されています。,ソースプログラムは、コンサル卜時にはシンタックスチェックされ、中間言語に変換されて、ヒープ領域に読み込まれます。,このため、大きなプログラムをコンサル卜するにはかなりの時間を要します。,それに対して、ここで説明する保存方法はヒープ領域の格納イメージをそのままバイナリファイルに保存(save)し、復元(restore)する時もそのまま読み込みますので、比較的早く読み込む事ができます。,5-6-1.セーブ,AZ-Prologでは、ヒープ領域の格納イメージをバイナリファイルに保存する事を「セーブ(save)」と呼んでいます。,具体的には「save/1」という述語を実行します。,例えば、現在のヒープ領域の格納イメージを「 'heap.bin' 」というバイナリファイルにセーブするには、,| ?-save('heap.bin').↓,yes,| ?-,とします。,このときのファイルの拡張子は機能上何でも構いませんが、便宜上「'.bin'」という拡張子を付けるようにする事をお薦めします。,5-6-2.リストア,セーブされたバイナリファイルをヒープ領域に読み込んで復元することを「リストア(restore)」と呼びます。,具体的には「restore/1」という述語を実行します。,リストアすると、ヒープ領域の内容がバイナリファイルの内容(セーブしたときのヒープ領域の内容)とそっくり入替わります。,例えば、前項でセーブした「 'heap.bin' 」というバイナリファイルをリストアするには,| ?-restore('heap.bin').↓,top_level,| ?-,とします。,この例の様に「restore/1」を実行すると、強制的にインタプリタのトップレベルに戻ります。,したがって、この述語の呼び出しがプログラム中にあると、これを実行した時点でプログラムの実行を中断してトップレベルに戻ります。,プログラム中で「restore/1」を呼び出し、かつ、そのプログラムの実行を中断せずに継続させる事は普通には無理ですが、「d_keyback/1」を使って、「restore/1」に続いて実行すべき処理に相当する質問(起動コマンド)の文字列をキーバッファに入れておくと、「restore/1」が実行されて強制的にインタプリタのトップレベルに戻ったときにその文字列が自動的に入力されて、リストアされたプログラムにある”継続すべき処理”が起動されます。,これにより、見た目にはプログラムは継続されているように見えます。,例えば、あるプログラム中で「 'test.bin' 」を読み込んでその中に登録されている「 go 」述語を実行するには・ ・ ・,…,d_keyback(''go.^ M''),restore('test.bin').,というゴール列を書いておきます。このゴール列を書く場所は特に制限はありませんが、実行時にはこれ以降は決して実行される事はありませんので、このゴール列を書く場所は実質的にプログラムの最後に限定されます。,このゴール列が実行されると、現在カーソルのある行のすぐ下の行から,top_level,| ?-go.,と表示され、ゴールgoが実行されることが確認できます。,またAZ-Prologでは、ヒープ領域を十分大きくとれる為、プログラムの実行中にバイナリファイルをヒープ領域に読み込む必要はあまりないでしょう。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_7","title":"5-7.日本語処理と漢字モード","text":"5-7.日本語処理と漢字モード,AZ-Prologでは、漢字を含む日本語のデータは勿論、プログラム中にもアトムや変数名に使う事ができます。,一般に漢字を表すコードはマルチバイトで表しますが、これを入出力時に1バイトづつに分けて扱うか、マルチバイトをまとめた整数として一括にして扱うかを「漢字モード」で決定します。,マルチバイトをまとめた整数として一括にして扱うモードを「漢字モード = on」、1バイトずつに分けて扱うモードを「漢字モード = off」とします。,漢字モードは、組込述語の「kanji_mode/2 」で設定・変更できます。,デフォルト(インタプリタ起動直後の設定)は「漢字モード = on」です。,具体的な漢字モードの違いは、「name/2 」及び一文字入力系述語から漢字コードが返される場合の値が、「漢字モード = on」のときは漢字一文字分が一つの整数値であり、「漢字モード = off」のときは漢字一文字分が二つの8ビット整数値(Shift-JISの場合。UTF-8では三つか四つ)であるところです。,<例:漢字モードによるname/2 の動作の違い (Windows版Shift-JISの場合)>,| ?-kanji_mode(X,X).↓,X = on↓,yes,| ?-name(漢,X).↓,X = [35519]↓,yes,| ?-name(X,[35519]).↓,X = 漢↓,yes,| ?-kanji_mode(X,off).↓,X = on↓,yes,| ?-name(漢,X).↓,X = [138,191]↓,yes,| ?-,もう一つ、漢字モードに関係して注意が必要な事があります。,それはエディタバッファをデータバッファとしてファイルの様に使った場合です。,エディタバッファに「copy0/0」述語(AzEditのCTRL-X CTRL-Vコマンドも同じ)を使ってデータを書き込んで、一文字入力系述語で読み出す場合の漢字コードの扱いは現在の漢字モードに依らず、「copy0/0」述語を使ってデータを書き込んだ時点での漢字モードによって決定されます。,例えば、「漢字モード = on」の状態でエディタバッファに「copy0/0」述語を使ってデータを書き込んだ場合は、現在の漢字モードに関わらず一文字分の漢字コードが一つの整数値で返されます。,逆に「漢字モード= off」の状態でエディタバッファに「copy0/0」述語を使ってデータを書き込んだ場合は、現在の漢字モードに関わらず、一文字分の漢字コードが複数の8ビット整数値で返されます。,通常は「漢字モード = on」の状態のままで何ら差し支えありません。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_8","title":"5-8.ロギング","text":"5-8.ロギング,AZ-Prologのインタプリタは、コンソール出力の記録をファイルにとる機能を持っています。,「log/0」を実行すると、それ以後のコンソールに対する出力がカレントディレクトリの「PROLOG.LOG」というファイルに付け加えられます。(これを「ログをとる」または「ロギング」と呼びます。),また「log(ファイル名)」を実行すると指定されたファイルにログをとります。,<例>,| ?-log('a.log').↓,yes,| ?-write(abcdefg).↓,abcdefg,yes,| ?-nolog.↓,yes,| ?-halt.↓,C:¥azpc> type a.log↓,yes,| ?-write(abcdefg).,abcdefg,yes,| ?-nolog.,C:¥azpc>,このように、ロギングを停止させるときには「nolog/0」を実行します。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_9","title":"5-9.エラー","text":"5-9.エラー,この節では、インタプリタがエラーに対してどのようなメッセージを出力するかを解説します。,5-9-1.構文エラー,コンソールから入力された質問やコマンドに構文エラーがある場合には、コンソールに以下の情報が表示されます。この場合はエラー行は明白です。,Syntax error,Prologソースファイルをコンサルト(またはリコンサルト)したり、コンソールから複数行をまとめて入力する(「5-3-1.コンソールからのプログラム入力」参照)場合は、どのファイルの何行目でエラーが検出されたか、その行の構文解析のどの時点でエラーが検出されたか(行の先頭からその位置までの節情報)が以下の書式で表示されます。  ,File =,[ファイル名 / 行番号],Here!>>,エラーの見つかった節(エラー検出位置まで),コンサルトでは複数ファイルを指定でき(:-['ファイル名1,ファイル2,...'].)、コンサルト内部で更に別のファイルをコンサルトする可能性もありますので、これらの情報はエラー箇所を特定する助けになります。,構文エラー(Syntax error)が検出されなかった行(節)、もしくはエラー検出された位置の次の文字から行末までの部分(これも構文エラーがない場合のみ)はヒープ領域に登録されますが、その際に起こり得るエラーは主に以下の2つです。エラー情報表示の書式は構文エラーの場合と同じです。,Illegal clause,節として認められない。,Builtin or C pred exist,既存の組込述語を再定義しようとした。,以下にエラーを含んだ2行だけのPrologソースファイルを読み込む簡単な例を示します(ファイル名をsyntaxerror.plとします)。,a:-b,c d,e.write(X):- puts(X).,このファイルをAZ-Prologインタプリタからコンサルトしてみます。,| ?-['syntaxerror.pl'].,Syntax error,File = [syntaxerror.pl / 1],Here!>> a:-b,c d,,Builtin or C pred exist,File = [syntaxerror.pl / 3],Here!>> write(X):- puts(X).,yes,| ?-listing.,e.,yes,| ?-,ソースファイルの1行目では、cとdの間にカンマがなく、スペースになっています。dに続くカンマを検出した時点でエラーと認識され、これが「 Here!>> 」以下に表示されています。この行には未だ残りの部分「 e. 」があります。この部分も引き続き構文チェックされますが、問題がないのでヒープ領域にアサートされます。上記の例でlisting/0を実行した時に表示されている「 e. 」はこの部分に該当します。,ソースファイル2行目は、述語write/1を定義しようとしています。構文エラーはないので、そのままアサートしようとしますが、write/1は組込述語なので、エラーになります。,シンタックスエラーもアサート時のエラーも、ピリオドの次の空白文字でエラーを認識するので、表示された行番号よりも前の行にエラー原因がある場合があります。,コンサルトされるファイルの中に「 :- 」や「 ?- 」で始まるゴールの実行が記述されている場合は、実行時に起こり得るあらゆるエラーが起きる可能性があります。,コンサルトで指定されたファイルが存在しない場合は、以下のようなエラーになります(ファイル名を仮にaaa.plとします)。,| ?-['aaa.pl'].,Can't see the file ---- Backtrace,[aaa.pl] ?-",本パッケージに付属するエディタAzEditで構文エラーを見つけることもできます。AzEditでソースファイルを読み込んで、そこからコンサルト(またはリコンサルト)した場合に構文エラーを発見すると、コンサルト(またはリコンサルト)を中止してカーソルがその次の文字に移動します。,また、AZ-Prologコンパイラ(azpc)で構文をチェックすることもできます。,5-9-2.実行時のエラー,実行時にエラーが発生した場合、インタプリタはエラーメッセージを表示した後、エラーを起こしたゴールがどのようにして呼び出されたのかを表示します。(エラーが起きたゴールが、どのようにして呼び出されたのかを逆に辿ることをバックトレースといいます。),それによってエラーが起こった原因を推測することができます。,この時に表示される情報量は、次項で説明する「エラーモード」によって設定されます。,通常、エラーが起きた場合(「errorset/2」によってエラーがトラップされないとき)、インタプリタはプログラムの実行を強制的に終了し、質問を発したトップレベルまで戻します。それまでオープンされていたファイルはすべてクローズされます。,ただし、「errorset/2」によってトラップされた場合は、ファイルはクローズされません。,<例>,| ?-listing.↓,a(X) :-,b(X).,a(X).,b(X) :-,Y is X+1,,write(Y).,yes,| ?-a(a).↓,Illegal Arithmetic expression ---- Backtrace,is(_6,+(a,1)) b(a) a(a) ?-,| ?-,最後の「 ?- 」はインタプリタが質問によって起動された事を示します。,5-9-3.エラーモード,エラーモードとは、エラーが起きた時の画面に出力される情報量を設定するモードです。,つまり、デバッグ時には出来るだけ多くの情報が要求され、反対にアプリケーション実行時には処理系からの(我がままな)メッセージによって画面が破壊されてしまい、かえって不都合な場合もあります。,このように、時と場合によってエラーに関する情報の量を変化させるのがエラーモードです。,エラーモードは組込述語「errormode/2 」を使って数値で指定します。それぞれのモードによって次の様な差があります。,0,なにも出力しません。,1,エラーメッセージのみを出力します。,2,エラーメッセージを出力した上でバックトレースし、今まで実行された述語をさかのぼって表示します。,3,デバッグモードがONのとき、エラーメッセージを出力した上でバックトレースし、今まで実行された節を遡ってそのレベル数と共に表示します。,前項の例を使って試してみましょう。,<例>,| ?-errormode(_,0).↓       ,_0 = 2↓,yes,| ?-a(a).↓,| ?-errormode(_,1).↓       ,_0 = 0↓,yes,| ?-a(a).↓,Illegal Arithmetic expression,| ?-errormode(_,2).↓       ,_0 = 1↓,yes,| ?-a(a).↓,Illegal Arithmetic expression ---- Backtrace,is(_14,+(a,1)) b(a) a(a) ?-,| ?-errormode(_,3).↓       ,_0 = 2↓,yes,| ?-a(a).↓,Illegal Arithmetic expression ---- Backtrace,is(_14,+(a,1)) b(a) a(a) ?-    ,| ?-debug.↓           ,yes,debug mode on,||?-a(a).↓,Illegal Arithmetic expression ---- Backtrace,*[0] Y_16 is a+1,[1] b(a) :-,Y_16 is a+1,,write(Y_16).,[2] a(a) :-,b(a).,[3] ?- a(a).,LOOP = 3,||?-,5-9-4.エラーメッセージの変更,AZ-Prologのエラーメッセージは、処理系内部に持っている訳ではなくエラーメッセージファイル「errmsg.db」に格納されています。,このファイルはprologのランダム(アクセス)ファイルです。,何等かのエラーが発生するとインタプリタは、エラーメッセージファイルを探して、そのエラー番号で検索し該当のメッセージを取得してコンソールに表示します。,従って、このエラーメッセージファイルが存在しないとメッセージを取得できない為、代わりにエラー番号をコンソールに表示します。,このファイルは、AZ-Prologのインストール・ディレクトリ下の「doc」というディレクトリにあります。,Linux版またはMac版では少し階層が深いですが、${AZProlog}/share/doc/azprolog/errmsg.dbがそれです。,<例:前々項と同じプログラムで、エラーメッセージファイルが存在しない場合>,| ?-a(a).↓,ERROR NO.26 ---- Backtrace,is(_6,+(a,1)) b(a) a(a) ?-,| ?-,エラーメッセージの代りにエラー番号がコンソールに表示される。,また、エラーメッセージファイルの内容を変更する事によって、エラーメッセージも変更が可能です。,例えば、エラーメッセージを日本語など英語以外の言語で表示する事も、エラーメッセージファイルの内容を変更するだけでできます。エラーメッセージファイルの内容変更は、AZ-Prologのインストール・ディレクトリ下の「system/pl」ディレクトリの「error.pl」で行ないます。"}); htmllist.push({"file":"manuals/manual_interpreter.html#interpreter_10","title":"5-10.述語の種類","text":"5-10. 述語の種類,AZ-Prolog の述語は、大きく分けて「組込述語」と「定義述語」があります。,以下ではそれらを更に細かく分類して説明します。,5-10-1.組込述語,「組込述語」は、実行プログラム(インタプリタ等)にあらかじめ組み込まれた述語です。,組込述語には、以下のように分類される三つの種類があります。,予め処理系が用意した組込述語,→「標準組込述語」,Prologのプログラムをコンパイルして追加した述語,→「コンパイル組込述語」,C言語のプログラムをコンパイルして追加した述語,→「Cリンク組込述語」,ただし、これ以降単に「組込述語」と記載されている場合は、「標準組込述語」を指すものとします。,標準組込述語の使い方は、マニュアルの「述語リファレンス」を、コンパイル組込述語の作り方については「7.コンパイラ」を、「Cリンク組込述語」の作り方(C言語のプログラムとのリンク方法)については「8.C言語インターフェース」をそれぞれ参照してください。,5-10-2.定義述語,「定義述語」はPrologプログラムのままヒープ領域に定義された述語です。,★ 「システム述語」と「ユーザ述語」,AZ-Prologでは定義述語をさらに「システム述語」と「ユーザ述語」の2つに分けて扱います。,定義述語は、普通listingによってプログラムのリストを表示したときに出力されます(「組込述語」はその種類に関わらず出力されません)。しかし、既に多くのプログラムで共通に使われ安定した述語ライブラリなどは、listingをとったときに出力されない方が望ましいでしょう。,AZ-Prologではこのような述語を「システム述語」として登録しておくとlistingによって出力されなくなります。「システム述語」に対して、通常listingによって出力される述語を「ユーザ述語」と呼びます。,★システムモード,このシステム述語を定義するモードを「システムモード」と呼びます。「システムモード」に対して通常のモードを「ユーザモード」と呼びます。,逆に言えば「ユーザモード」で入力・定義された述語は「ユーザ述語」であり、「システムモード」で入力・定義された述語が「システム述語」になります。,なお、前述した通り、通常モード(ユーザモード)では「システム述語」はlistingによって出力されませんが、「システムモード」に入ると「システム述語」はlistingによって出力され、逆に「ユーザ述語」は出力されなくなります。,また、システムモードで定義された述語(システム述語)は「s_new/0」を実行しても削除されません。この性質を利用して、次のような使い方が考えられます。例えば「プログラムをすべてシステム述語にしておいて、データ(知識)をユーザ側に入れておくと、一連の動作が終了した後で“s_new/0”を実行するだけで間違い無くデータを削除する」など。,[ユーザモード] [システムモード]の切換えは「s_mode/2」を実行します。,| ?-s_mode(_,on).↓,_0 = off↓,yes,! ?-,そうするとプロンプトが変わってシステムモードになったことを表示します。,逆に、ユーザモードへ戻すには「s_mode(_,off)」を実行します。,! ?-s_mode(_,off).,_0 = on,yes,| ?-,[同名/同アリティ]の異種述語は、システムモードとユーザモード間で共存出来ません。,つまりユーザモードにおいて、既に登録されているシステム述語と同じ述語名と同じアリティの頭部を持つ節を入力しようとするとエラーとなります。,逆にシステムモードにおいて、既に登録されているユーザ述語と同じ述語名と同じアリティの頭部を持つ節を入力しようとしてもエラーとなります。,また、これらのモードに関係なく、組込述語と同じ述語名と同じアリティの頭部を持つ節を入力しようとしてもエラーとなります。,まとめて言えば、既に登録されている述語と違う種類の同じ述語名と同じアリティの頭部を持つ節を入力しようとするとエラーになります。"}); htmllist.push({"file":"manuals/manual_debugging.html#debugger","title":"6-1.概要","text":"6-1.概要,この章では、AZ-Prologインタプリタに組み込まれているデバッガの使い方について説明します。このデバッガは虫取りだけでなく、インタプリタの動作そのものの理解の助けにもなると思います。,まず、次項の「6-2.デバッガの基本的な使い方(トレースとスパイ)」においてデバッガの基本的な使い方を解説します。"}); htmllist.push({"file":"manuals/manual_debugging.html#debugger_2","title":"6-2.デバッガの基本的な使い方(トレースとスパイ)","text":"6-2.デバッガの基本的な使い方(トレースとスパイ),AZ-Prologのトレースは、インタプリタが今現在何をしているのかの情報をすべてターミナルに出力します。表示される情報量は多く、どのような局面で情報を表示するかは設定で変えられるようになっています。情報量を選択することも可能です。,なにはともあれ、早速使ってみましょう。,その前に、,| 理解する(松尾さん,ワビ). /*松尾さんは“ワビ”がわかる。*/,| 理解する(松尾さん,サビ). /*松尾さんは“サビ”がわかる。*/,| 理解する(ブリキ屋さん,サビ). /*ブリキ屋さんは“サビ”がわかる。*/,| 理解する(X,風流):- 理解する(X,ワビ). /*“ワビ”がわかる人は風流を理解する。*/,| 理解する(X,風流):- 理解する(X,サビ). /*“サビ”がわかる人は風流を理解する。*/,というプログラムを何等かの方法で入力してください。このサンプルは他の章でも説明に多用しているプログラムです。,邪魔なコードが混じっていない5-4-1.の例の部分を利用する方法もあります。正しく入力出来たか確かめてみます。,| ?-listing.,理解する(松尾さん,ワビ).,理解する(松尾さん,サビ).,理解する(ブリキ屋さん,サビ).,理解する(X,風流) :-,理解する(X,ワビ).,理解する(X,風流) :-,理解する(X,サビ).,yes,| ?-,まず、トレースを使ってみます。,| ?-trace.,yes,debug mode on,||?-,これで、次の質問からトレースがかかります。 厳密には「trace/0」が成功した時点からトレースがかかっています。プロンプトが「| ?-」から「||?-」に変わったのは、インタプリタがデバッグモード( 「6-3.デバッグモード」参照)で動いているということを知らせるためです。(トレースまたはスパイをかけると自動的にデバッグモードになります。 ),また、「LOOP=」に続く整数値はインタプリタがゴールを実行する際に述語を呼出した回数(下のトレースの実行例で、Tryした回数と言えば分かり易いですね。)です( 「6-4-3.ループカウンタ」参照)。,||?-理解する(ブリキ屋さん,風流).,[1] 0 Try : 理解する(ブリキ屋さん,風流) ? (1),Match : 理解する(ブリキ屋さん,風流) :-,理解する(ブリキ屋さん,ワビ). (2),[2] 1 Try : 理解する(ブリキ屋さん,ワビ) ? (3),[2] 1 Fail : 理解する(ブリキ屋さん,ワビ) (4),[1] 0 Pop : 理解する(ブリキ屋さん,風流) (5),[1] 0 Retry : 理解する(ブリキ屋さん,風流) ? (6),Match : 理解する(ブリキ屋さん,風流) :-,理解する(ブリキ屋さん,サビ). (7),> (8),[1] 0 Try : 理解する(ブリキ屋さん,サビ) ? (9),Match : 理解する(ブリキ屋さん,サビ). (10),[1] 0 Succ : 理解する(ブリキ屋さん,サビ) (11),yes,LOOP = 3,||?-,これらは以下のようなことを意味します。,(1)これから「理解する(ブリキ屋さん,風流)」を実行します(Try)。,(2)「理解する(ブリキ屋さん,風流)」と単一化可能な頭部を持つ節がみつかりました。それはこの節です(Match)。,(質問: 「理解する(ブリキ屋さん,風流)」を「理解する(ブリキ屋さん,ワビ)」に置き換えます。),(3)これから「理解する(ブリキ屋さん,ワビ)」を実行します(Try)。,(4)「理解する(ブリキ屋さん,ワビ)」と単一化可能な頭部を持つ節はありません(Fail)。,(5)「理解する(ブリキ屋さん,風流)」を実行しようとして、途中までうまくいきましたがだめでした。内部状態を元に戻します(Pop)。,(6)「理解する(ブリキ屋さん,風流)」 の別解を探します(Retry)。,(7)「理解する(ブリキ屋さん,風流)」に別の選択肢がありました。(Match)。,(質問: 「理解する(ブリキ屋さん,風流)」を「理解する(ブリキ屋さん,サビ)」に置き換えます。),(8)この節は定義の最終節です( >)。,(9)「理解する(ブリキ屋さん,サビ)」を実行します(Try)。,(10)「理解する(ブリキ屋さん,サビ)」と単一化可能な頭部を持つ節がみつかりました。それはこの節です(Match)。,(11)「理解する(ブリキ屋さん,サビ)」の実行に成功しました(Succ),実行例の様に、デバッガの出力するメッセージには「Try」「Match」「Succ」「Fail」「Pop」「Retry」という、実行動作の局面を表す文字列が含まれています。,それぞれがどのような場合に出力されるのか、以上の説明によっておおよそ理解してもらえたと思います。,(詳しくは「6-4.デバッガから出力される情報」を参照してください。),トレースを終えるには次のようにします。,||?-notrace.,[1] 0 Try : notrace ?,>,yes,LOOP = 1,||?-,「《BUILTIN CALL》」というのは「Try」した「notrace」が組込述語であった事を表しています。,トレース終了後のプロンプトを見て気付かれたと思いますが、デバッグモードは解除されていません。これを解除するには次のようにします。,||?-nodebug.,yes,debug mode off,| ?-,トレースは上の例でも分るように、ゴール(質問)の実行の最初から最後までに呼び出された全述語の実行の過程・結果を表示します。,従って、上の例ように簡単なプログラムの場合はともかく、ちょっと大きなプログラムになると出力される情報は膨大な量になってしまいます。,その例として次のサンプルプログラムを試してみましょう。このファイルはAZ-Prologのインストールディレクトリ下の「sampleother」に入っています(Linux版ではshare/azprolog/sample/other)。,| ?-[-'queen.pl'].,これはよく知られた8クイーンを解くプログラムです。,ただし、このプログラムは8クイーンだけではなくnクイーン(即ち、互いに取り合えないようなn×nの盤上のn個のクイーンの配置を求める問題です。)を解くことができます。,| ?-queen(4,X).,X = [2,4,1,3],yes,| ?-,試しに、これにトレースをかけてみてください。,| ?-trace.,yes,debug mode on,||?-queen(4,X).,[1] 0 Try : queen(4,X_5) ?,Match : queen(4,X_5) :-,generate(4,L1_11),,put(L1_11,[],X_5).,[2] 1 Try : generate(4,L1_11) ?,Match : generate(4,[4|L_15]) :-,N1_17 is 4-1,,generate(N1_17,L_15).,[3] 2 Try : N1_17 is 4-1 ?,>,[3] 2 Succ : 3 is 4-1,>,[2] 1 Try : generate(3,L_15) ?,Match : generate(3,[3|L_26]) :-,N1_28 is 3-1,,generate(N1_28,L_26).,[3] 2 Try : N1_28 is 3-1 ?,>,[3] 2 Succ : 2 is 3-1,>,[2] 1 Try : generate(2,L_26) ? a   ,LOOP = 6,||?-,おそらく、うんざりしてきたと思います。,(デバッガが「……?」ときいてきたときに「a 」を入力すればインタプリタのトップレベルに戻ります。),こんなときのためにスパイがあります。 (下図の実行例で、?の後に縦棒のように見えているのは小文字のL(エル)です。Lコマンドについては「6-5」を参照してください。),||?-notrace.,[1] 0 Try : notrace ?,>,yes,LOOP = 1,||?-spy put/3.,yes,LOOP = 1,||?-queen(4,X).,[1] 0 Try : put([4,3,2,1],[],X_5) ? l ,[3] 1 Try : put([3,2,1],[4],X_5) ? l,[5] 2 Try : put([3,1],[2,4],X_5) ? l,[5] 2 Pop : put([3,1],[2,4],X_5),[5] 2 Retry : put([3,1],[2,4],X_5) ? l,[5] 2 Fail : put([3,1],[2,4],X_5),[5] 2 Try : put([3,2],[1,4],X_5) ? l,[7] 3 Try : put([2],[3,1,4],X_5) ? l,[7] 3 Pop : put([2],[3,1,4],X_5),[7] 3 Retry : put([2],[3,1,4],X_5) ? l,[7] 3 Fail : put([2],[3,1,4],X_5),[5] 2 Pop : put([3,2],[1,4],X_5),[5] 2 Retry : put([3,2],[1,4],X_5) ? l,[5] 2 Fail : put([3,2],[1,4],X_5),[3] 1 Pop : put([3,2,1],[4],X_5),[3] 1 Retry : put([3,2,1],[4],X_5) ? l,[3] 1 Fail : put([3,2,1],[4],X_5),[3] 1 Try : put([4,2,1],[3],X_5) ? l,[5] 2 Try : put([4,2],[1,3],X_5) ? l,[7] 3 Try : put([2],[4,1,3],X_5) ? l,[9] 4 Try : put([],[2,4,1,3],X_5) ? l,[9] 4 Pop : put([],[2,4,1,3],X_5),[9] 4 Retry : put([],[2,4,1,3],X_5) ? l,[9] 4 Succ : put([],[2,4,1,3],[2,4,1,3]),[7] 3 Succ : put([2],[4,1,3],[2,4,1,3]),[5] 2 Succ : put([4,2],[1,3],[2,4,1,3]),[3] 1 Succ : put([4,2,1],[3],[2,4,1,3]),[1] 0 Succ : put([4,3,2,1],[],[2,4,1,3]),X = [2,4,1,3],yes,LOOP = 124,||?-,スパイはトレースすると、大量に出力される情報を人間が指定したものだけに制限します。上の例は、述語queen/2の中で呼ばれるput/3だけに限定して、その実行の流れを辿ったものです。(スパイは、機械語プログラムのデバッグ時によく使用されるブレークポイントに相当します。),また当然ですが、複数個の述語にスパイを同時にかけることもできます。,スパイがどの述語にかかっているかは次のようにして知ることができます。,||?-debugging.,>,Debug Mode = debug (1),Unknown = fail   (2),Spy Points = put/3 (3),Command Point = Try Retry (4),Display Point = Try Match Succ Fail Pop Retry (5),Verbose Mode = middle (6),yes,LOOP = 1,|| ?-,このように「debugging/0」によって,(1)現在デバッグモードか否か、もしくはトレースがかかっているかどうか。,(2)定義されていない述語を実行しようとしたとき、失敗するかトレースを始めるか。,(3)スパイがかかっている述語。,(4)トレース時にどの局面でコマンド入力を受け付けるか。(leash/1で設定。設定方法は「6-5-1.」を参照してください。),(5)トレース時及びスパイにおいてどの局面を表示するか。(leash1/1で設定。設定方法は「6-4-3.(1)」を参照してください。),(6)トレースの際に出力する情報量。( leash2/1 で設定。設定方法は「6-4-3.(2)」を参照してください。,という6つの情報を得ることができます。,スパイの外しかたには2通りあります。ひとつは以下のような方法です。,||?-nospy put/3.,yes,LOOP = 1,||?-,もうひとつは「nodebug/0」によってデバッグモードを解除する方法です。,この述語は、デバッグモードを解除すると同時にすべてのスパイを外します。,||?-nodebug.,yes,debug mode off,| ?-,以上は「述語名とアリティ」を指定したスパイポイントの設定・解除ですが、この他に「述語名のみ」「述語名/アリティ/節順位」「述語名/アリティ/節順位/ボディ部のゴール順位」を指定したスパイポイントの設定・解除もできます。, <例  「述語名/アリティ/節順位」を指定したスパイポイントの設定>,| ?-['trans.dcg'].          ,yes,| ?-listing(jn).,jn([n,'I'],[私|_0],_0).,jn([n,you],[あなた|_0],_0).,jn([n,arrow],[矢|_0],_0).,jn([n,flies],[蝿|_0],_0).,jn([n,flies],[てんぷら|_0],_0).  ,jn([n,time],[時|_0],_0).,jn([n,like],[好み|_0],_0).,yes,| ?-spy jn/3/5.           ,yes,debug mode on,||?-debugging.     ,>,Debug Mode = debug,Unknown = fail,Spy Points = jn/3/5        ,Command Point = Try Retry,Display Point = Try Match Succ Fail Pop Retry,Verbos Mode = middle,yes,LOOP = 1,||?-trans("time flies like an arrow",X,Y).,X = [s,[np,[n,time],[np,[n,flies]]],[vp,[vt,like],[np,[det,a],[n,arrow]]]],,,Y = [時,の,蝿,は,ひとつの,矢,を,好む];       ,[12] 3 Retry : jn([n,flies],_4_387,[は|_4_377]) ?,Match : jn([n,flies],[てんぷら,は|_4_377],[は|_4_377]). ,[12] 3 Succ : jn([n,flies],[てんぷら,は|_4_377],[は|_4_377]),[10] 2 Succ : jnp([np,[n,time],[np,[n,flies]]],[時,の,てんぷら,は|_4_377],[は|,_4_377]),[13] 2 Try : jvp([vp,[vt,like],[np,[det,a],[n,arrow]]],_4_377,[]) ? l,[13] 2 Try : jvp([vp,[vt,like],[np,[det,a],[n,arrow]]],_4_377,[]) ? l,X = [s,[np,[n,time],[np,[n,flies]]],[vp,[vt,like],[np,[det,a],[n,arrow]]]],,,Y = [時,の,てんぷら,は,ひとつの,矢,を,好む],yes,<例 「述語名/アリティ/節順位/ボディ部のゴール順位」を指定したスパイポイントの設定>,| ?-listing.,a.,a(1) :- true, write(a1), nl.,a(2) :- true, write(a2), nl. ,a(3) :- true, write(a3), nl.,yes,| ?-spy a/1/2/2.,yes,debug mode on,||?-debugging.,>,Debug Mode = debug,Unknown = fail,Spy Points = a/1/2/2,Command Point = Try Retry,Display Point = Try Match Succ Fail Pop Retry,Verbose Mode = middle,yes,LOOP = 2,||?-a(X),fail.,a1,[2] 1 Try : write(a2) ? p    ,1: write(a2),0: a(2) :-,true,,*> write(a2),     ,nl.,Goal: ?- a(2),fail."}); htmllist.push({"file":"manuals/manual_debugging.html#debugger_3","title":"6-3.デバッグモード","text":"6-3.デバッグモード,このインタプリタにはデバッグモードがあります。(デバッグモードに対して普通の状態のことをノーマルモードと呼びます。),前項のようにトレースかスパイをかけると自動的にデバッグモードに入りますが、「notrace/0」や「nospy /fy」を実行してトレースまたはスパイを終了してもデバッグモードから抜けません。,つまり、トレースもスパイもかかっていないデバッグモードの状態がある訳です。,この状態では、ループカウンタを表示する以外、見た目はほとんどノーマルモードと変りません。,ただし、トレースに移行した場合のデバッグ情報を保持するため、LastCallOptimizationを抑止しますのでスタックの消費が増えます。,また、スパイポイントを調べたり、CallCountの蓄積などをおこなうため、実行速度は大幅に(約80%程度)落ちます。,従って、デバッグ時はスタックを多めにとり、デバッグが終わって実際にプログラムを走らせる時には、必ずノーマルモードまたはコンパイルして動かすようにしてください。,デバッグモードか否かを知るには2つの方法があります。,(1)インタプリタのコマンドレベルのプロンプトを見る。,・ノーマルモードの場合,「| ?-」(ユーザモード)あるいは「! ?-」(システムモード),・デバッグモードの場合,「||?-」(ユーザモード)あるいは「!!?-」(システムモード),(2)debugging/0を実行してデバッグモードか否かをコンソールに表示する。,ノーマルモードからデバッグモードにするには「debug/0、spy /fy、trace/0」のうちどれかを実行します。,逆に、デバッグモードからノーマルモードに戻すには「nodebug/0」を実行します。,プログラムの実行中においては、モードの移行はおこなわれませんので、通常はトップレベルにおいて質問、コマンドで与えます。ゴールの中に書かれたこれらのコマンドのうちモードの移行に関するものは、プログラムが終了しトップレベルに戻ってから移行がおこなわれます。ゴールとして「trace/0」を含むプログラムは初めからデバッグモードで実行させてください。,また、デバッグモードのまま「halt/0」「halt/1」でインタプリタを終了しても特に問題ありません。"}); htmllist.push({"file":"manuals/manual_debugging.html#debugger_4","title":"6-4.デバッガから出力される情報","text":"6-4.デバッガから出力される情報,このデバッガでは、インタプリ夕の基本的な動作の局面を「Try、 Match、Succ、Fail、Pop、Retry」の6つに分けています。ですので、まず「6-4-1.インタプリタの基本的な動作局面」で各局面について説明します。その上で、「6-4-2.局面ごとの出力情報」では、どの局面で何が出力され、それはどのような意味を表しているのかを説明します。「6-4-3.出力情報の制御」では、デバッガが情報を出力する局面を変更したり、情報量を変える方法を説明します。デバッガの出力中に含まれる「LOOP =」について理解して頂くため、ループカウンタについて「6-4-4.ループカウンタ」で解説しています。また、「6-4-5.述語コールカウンタ」では、プログラム実行中にどの述語が何回呼ばれたかの集計情報を表示し、バグの検出や実行効率の向上に役立てる機能について説明しています。,6-4-1.インタプリタの基本的な動作局面,前述した6つの局面のそれぞれがどういう局面なのか、その局面では何が表示され(ここでは簡単に)、この局面が終わってからどのような局面に制御が移っていくのかということについて説明します。,(1)Try,【局面】,インタプリ夕が次に実行すべきゴールに移る時。,【表示】,これから実行するゴールを表示します。,【遷移】,そのゴールが組込述語なら、対応する機械語コードを呼び出し、成功すれば「Succ」に、失敗すれば「Fail」に制御が移ります。定義述語なら、そのゴールと単一化可能な頭部を持つ節を探し、あれば「Match」に、なければ「Fail」に制御が移ります。,(2)Match,【局面】,「Try」で表示されたゴールと単一化可能であるような頭部を持つ節をみつけた時。,【表示】,単一化された節を表示します。,【遷移】,その節が単位節(ゴール列を持たない節)なら「Succ」へ。それ以外は、その節の本体の最初のゴールを「Try」しに行きます。,(3)Succ,【局面】,実行したゴールが成功した時。,【表示】,成功したゴールを表示します。,【遷移】,そのゴールが節の本体の最後のゴールなら、節の頭部が成功し「Succ」へ、続くゴールがあれば、そのゴールを「Try」しに行きます。,(4)Fail,【局面】,組込述語の実行に失敗した時。あるいは「Try」または「Retry」するゴールと単一化可能な頭部を持つ節がなかった時。,【表示】,失敗したゴールを表示します。,【遷移】,「Pop」へと移ります。,(5)Pop,【局面】,バックトラック(後戻り)している時。,【表示】,バック卜ラックして不用になったゴールを表示します。,【遷移】,別の選択肢(その頭部が「Pop」したゴールと単一化可能かどうかまだ調べていない節)が見つかるまで「Pop」が続き、見つかった時点で制御は「Retry」へ移ります。,(6)Retry,【局面】,別の選択肢(代替節)が見つかった時。,【表示】,代替節を実行するゴールを表示します(「Try」の表示と同じ)。,【遷移】,未だ調べていない節から探し始める以外は「Try」同じです。,6-4-2.局面による出力情報,トレースをかけると、インタプリタが6つの局面の内のどれかに達した時、その局面名と現在インタプリタが注目しているゴールまたは節を表示します。これによって、今現在インタプリタが何をしているかがわかります。,ただし、このとき表示されるゴールまたは節は、それらの定義イメージそのままではありません。各局面に共通することなので、局面ごとの出力の説明に移る前に、このことについて若干説明します。,デバッガがゴールや節の情報を表示する場合、その中に現れる変数に値が代入(ユニファイ)されていたら、変数の部分は変数名ではなくその値が表示されます。,<例>,||?-listing.,a(X) :-,write(X). /*節の定義イメージ*/,yes,LOOP = 1,||?-trace,a(b(c)). /*a(b(c))をトレース実行*/,[1] 0 Succ : trace,[1] 0 Try : a(b(c)) ?,Match : a(b(c)) :-,write(b(c)). /*節中の変数Xはb(c)に置換されている*/,>,[1] 0 Try : write(b(c)) ?,>,b(c) [1] 0 Succ : write(b(c)),[1] 0 Succ : trace,a(b(c)),yes,LOOP = 4,||?-,このように、述語a/1の定義中の変数Xは、トレース実行時には項b(c)にユニファイされるので、各局面で表示される節やゴールでは項b(c)に置き換えられた形で表示されています。,一方、上の例には含まれませんが、未代入の変数の場合は、元々の変数名の後に「_NN」(アンダスコア+領域の取られたセル番号)が付加された形で表示されます。同じ節中でこの形の表示が同じものは同じ変数を表すと考えてください。他の節に同名の変数があっても、セル番号が違ってきますから、別物であることが容易に分かります。,デバッガーから出力される情報は、Matchとそれ以外の局面で内容が異なります。以下にそれぞれの場合を説明しますが、ここに書かれているのは「標準的なdebug情報」についての内容です。それ以外の場合については、「6-4-3.(2)出力される情報量の選択」を参照してください。,(1)Match以外の局面の場合,即ち、Try、Succ、Fail、Pop、Retryの場合の出力情報は以下の通りです。,[シリアルナンバー] スタックの深さ 局面名 : ゴール,ここで、シリアルナンバーは「インタプリテーションが始まってからこのゴールを実行するまでの実際のゴールの積層数」です。,この値と次の「先祖系列スタックの深さ」の差が大きいほど、このゴールの手前に非決定性のゴールが多く含まれていることになります。,スタックの深さは「このゴールからトップゴールまでの先祖系列スタックの深さ」を表しています。(6-5-2.コマンド解説Pコマンド参照),[15] 1 Try:queen1(4,[4,3,2,1],[],Ⅹ,[],[])?,局面名は「Try」です。,シリアルナンバーが「15」で、スタックの深さは「1」です。,「?」を出力してコマンド(「6-5.デバッガのコマンド」参照)を要求しています。,(2)Matchの場合,Matchの場合の出力情報は以下の通りです。,Match:頭部がゴールと単一化された節,<例>,Match : put([4,3,2,1],[],L_14) :- select([4,3,2,1],S_22,D_24), safe([],S_22,S_22), put(D_24,[S_22],L_14).,6-4-3.出力情報の制御,ここではデバッガが情報を出力する局面を変更したり、情報量を変える方法を説明します。,(1)情報を出力する局面の選択,通常はすべての局面で情報が出力されますが、 「Try、 Match、Succ、Fail、Pop、Retry」のうち特定の局面に達したときのみ出力するようにleash1/1」によって設定することもできます。,「leash1(整数)」を実行すると、整数を2進数で表したときのビット0~5 (ビット0が最下位ビット:least significant bit)の6ビットの対応するビットが1である局面についてのみ出力されるようになります。ビットと局面の対応は以下の通りです。,Version 8 からは、r,p,f,s,m,t を含むアトムによる設定を追加しました。,r,p,f,s,m,t が、Retry  Pop  Fail  Succ  Match  tryに対応。順序は問わず、それ以外の文字は無視します。,?- leash1(rfpt).  ,ビット,5,4,3,2,1,0,局面,Retry,Pop,Fail,Succ,Match,Try,例えば、「leash1(4)」を実行すると「Succ」のときにしか出力しません。,また、「leash1(63)」を実行するとすべての局面について出力されます。,【注意】,組込述語については、その種類(「5-10-1.組込述語」参照)にかかわらずヒープ領域に節の実体が無い為、その実行過程は表示されません。この場合「《BUILTIN CALL》」と表示されます。,また、 ヒープ領域に定義された述語(定義述語)であっても、決定性述語(代替節のない述語)の場合は、6つの局面のうち「Retry」と「Pop」の情報は出力されません。,(2)出力される情報量の選択 ,トレースの際に出力する情報量は組込述語 leash2/1 で選択することができます。引数には0~3の整数値を与えます。数値の意味は以下の通りです。何もしなければ、デフォルトは1(標準的な情報出力)に設定されています。「6-4-2.局面ごとの出力情報」で解説した内容がこれに当たります。,0:最小のdebug情報, ,Match以外の局面でのゴール表示は「述語名/アリティ」のみ。,Matchの局面での節は何も出力されません。,1:標準的なdebug情報, ,「6-4-2.局面ごとの出力情報」を参照してください。,2:最大のdebug情報, ,標準的なdebug情報に加え、局面表示の直後に以下のような情報が出力されます。,「Try」「Retry」「Fail」「Pop」「Succ」 では該当ゴールの位置(親述語名/親述語アリティ/親述語の節順位/節中のゴール順位),「Match」ではMatchした述語定義の位置(述語名/アリティ/マッチした節の順位),【記述例】,| ?- listing.,| a:- b,c.,| a:- c.,| c.,| ?-leash2(2),trace.,yes,debug mode on,||?-a.,[1] 0 Try : TopGoal :a ?  ,Match : a/0/1 :       ,a :-,b,,c.,[2] 1 Try : a/0/1/1 :b ?   ,[2] 1 Fail : a/0/1/1 :b    ,[1] 0 Pop : TopGoal :a    ,[1] 0 Retry : TopGoal :a ?   ,Match : a/0/2 :       ,a :-,c.,<< LAST CALL >>,[1] 0 Try : a/0/2/1 :c ?   ,Match : c/0/1        ,c.,[1] 0 Succ : a/0/2/1 :c    ,yes,3:最大に追加されたdebug情報, ,最大のdebug情報(2)に加え、通常は出力されない次のトレースが可能になります。,・freezeされたゴールのトレース,・AZ-Prologコンパイラ(azpc)のオプション /debug でコンパイルされたコード(Cコード、バイトコード)のトレース,いずれかを選択するには以下のようにします。,<例:最小のdebug情報の場合>,?- leash2(0).,6-4-4.ループカウンタ,デバッグモードでは、ゴールから述語を呼出した回数をカウントする「ループカウンタ」が動作します。Prologのコマンドレベルから発せられる質問の実行が終了すると、そのカウントの結果が次の様に表示されます。,<例>queen.plが読み込まれているとします。,||?-q(8).,:,:,No.92,. . . Q . . . .,. Q . . . . . .,. . . . . . Q .,. . Q . . . . .,. . . . . Q . .,. . . . . . . Q,. . . . Q . . .,Q . . . . . . .,Total = 92,yes,LOOP = 116718,この機能を使って例えば、「同じ動作をする二つのプログラムのどちらが動作効率がいいか(どちらのプログラムがコールの回数が少なくてすむか)」というようなプログラム効率の検証ができます。,細かい話ですが、もう一つループカウンタを使っていて少し「あれ?」と思われる事があるかも知れません。,それでは、次の質問を実行してみましょう。,||?-true.,yes,LOOP = 1,||?-,これは true/0 という節(組込述語)を1回コールしたのですから納得できます。,問題は次の場合です。,||?-true,true.,yes,LOOP = 3,||?-,「true/0」を2回コールしたのですから「LOOP=2」となりそうですね。にも関わらず「LOOP=3」と表示されています。,これは、ゴールの区切りの「,」が文法上引数2個のオペレータとして扱われているため、インタプリタはこれを「','(true, true)」と解釈して、先ずこの「 ','/2 」をコール(実行)してからその引数のコール(実行)にかかる為です。,しかし、実際には上で紹介した様な「どちらが動作効率がいいか」というような相対的に比べる使い方をする場合は関係ない事ではあります。,6-4-5.述語コールカウンタ,述語コールカウンタを利用すると、プログラムを実行した際にどの述語(組込、ユーザ定義とも)が何回呼ばれているかをチェックすることができます。,<用途>,呼ばれるはずなのに表示されない、呼ばれるはずのない述語が表示される、などバグの検出,どの述語の負荷が高いか(すなわちCall回数が多いか)など、アルゴリズムの検討,論理的に等価なプログラムでもゴールの並び順によって大きく効率が違うことがあるので呼び出し述語量の検討,など,<使い方>,デバッグモードにおいて、次のような形で質問をします。実行するプログラムをゴールで与えます。通常モードではゴールは実行されますが、述語呼び出し回数の集計情報は表示されません。,||  ?- call_count_check(ゴール).,プログラム(ゴール)が終了してトップレベルに戻った時に、使われた各述語がそれぞれ何回呼び出されたかを表示します。ユーザ述語/システム述語/組込述語(これらについては「5-1.述語の種類」を参照)の順に集計・表示されます。,<使用例>,$ prolog_c -c queen.pl,AZ-Prolog Version 8.xx (Linux/x64) ,Copyright (C) SOFNEC CO., LTD. 1987-2015,| ?-debug.,yes,debug mode on,||?-call_count_check(q(4)).,No.1, . Q . ., . . . Q, Q . . ., . . Q ., ,No.2, . . Q ., Q . . ., . . . Q, . Q . ., ,Total = 2,===CALL COUNT===,exec_status=succ,==== user ====,safe/3 => 52,select/3 => 49,disp2/1 => 20,disp1/2 => 20,put/3 => 17,disp/2 => 10,generate/2 => 5,queen/2 => 1,=== system ===,=== builtin ===,is/2 => 106,¥== /2 => 64,write/1 => 38,e_register/3 => 4,nl/0 => 2,yes,LOOP = 404,|| ?-"}); htmllist.push({"file":"manuals/manual_debugging.html#debugger_5","title":"6-5.デバッガのコマンド","text":"6-5.デバッガのコマンド,デバッガがある局面に達してその局面に関する情報をコンソールに出力した後に「?」を表示した場合には、デバッガに対してコマンドを入力することができます。(逆に、このような場合にしかコマンドを入力することはできません。),どの局面でコマンド入力を受け付けるかは、設定によって変更することができます。まず、「6-5-1.コマンド入力局面の選択」でこの設定方法を説明し、次に「6-5-2.コマンド解説」で、使用できるデバッガのコマンドについて解説していきます。,6-5-1.コマンド入力局面の選択,デフォルトでは、「Try」「Retry」の2つの局面にインタプリタが達したときのみコマンド入力を受け付けるようになっています。,どの局面に達したときにトレース情報を表示するかを「leash1/1」によって変えられるのと同じように(前項参照)、どの局面のときコマンド入力を受け付けるかも「leash/1」によって変更する事が出来ます。,局面とビットとの対応は、前項の「leash1/1」と同じです。,Version8からは、r,p,f,s,m,t を含むアトムによる設定を追加しました。,r,p,f,s,m,t が Retry  Pop  Fail  Succ  Match  tryに対応。順序は問わず、それ以外の文字は無視します。,?- leash(rfpt).  ,ビット,5,4,3,2,1,0,局面,Retry,Pop,Fail,Succ,Match,Try,また、やはり対応するビットが「1」である局面のときのみコマンド入力を受け付けます。,6-5-2.コマンド解説 ,デバッガのコマンドには以下のようなものがあります。,(インタプリタがどの局面にさしかかっているかによって使えるコマンドも変わってきます。すべての局面では使えないコマンドについては、コマンド解説の最初に「使用可能局面:」でこれを示します。),creep,インタプリタが次の局面に達し次第、その局面に関する情報をコンソールに出力します。連続してこのコマンドを使うと、インタプリタの動作に関するすべての情報がコンソールに出力されます。,;(セミコロン),retry,【使用可能局面】「Match」「Succ」,「Match」において使われた場合には、単一化可能な頭部を持つ別の節を探しにいきます。,「Succ」使われた場合には、表示されたゴールの別の可能性を試します。,どちらの場合にも、その直後の実行に失敗してバックトラックした場合とまったく同じように動きます。そのような状態を強制的に作りだしているわけです。,A,abort,アボー卜します。,プログラムの実行を強制的に打ち切り、インタプリタのトップレベルに戻ります。,ただし、「errorset/2」または「consult/1」「reconsult/1」の中でこのコマンドが使われた場合には、そこでトラップされます。,「abort/0」を実行した場合とまったく同じです。,B,break,プログラムの実行を中断し、新しいブレークレベルに入ります。 Aコマンドとは異なり、「unbreak/0」によって実行を再開することができます。デバッグの途中で、「leash/1」「leash1/1」などを使ってデバッガの出力情報の量をコントロールしたり、プログラムをエディットしたりする時に使います。,「break/0」を実行した時とまったく同じように動作します。,D,dump stack,スタックの最底部から最上部までのゴールを全て木構造で表示します。,”[シリアルナンバー] スタックの深さ: ゴール”の形式で表示され、”>*”が現在のスタック位置を表します。,[シリアルナンバー] はトレース時の「インタプリテーションが始まってからの実際のゴールの積層数」と同じです。,”スタックの深さ:”は逆順ですが、Pコマンドと同じ現在ゴールの直系列で「現在ゴールからトップゴールまでの先祖系列の深さ」です。,”スタックの深さ:”がついていない行はオルタナティブの残っている兄弟ゴールおよびその子孫にあたります。,[シリアルナンバー] はバックトラックパス(番号の小さい方向に向かって順番にバックトラックする)でもあります。,6-5-3. でこのコマンドを使ったスタックの状態を調べる例を挙げています。,<例>,[14] 1 Try : e_register(0,N1_10,N1_10+1) ? d,[1] 0: q(4),[2] ┣ queen(4,[2,4,1,3]),[3] ┃ ┗ put([4,3,2,1],[],[2,4,1,3]),[4] ┃ ┣ select([4,3,2,1],3,[4,2,1]),[5] ┃ ┃ ┗ select([3,2,1],3,[2,1]),[6] ┃ ┗ put([4,2,1],[3],[2,4,1,3]),[7] ┃ ┣ select([4,2,1],1,[4,2]),[8] ┃ ┃ ┗ select([2,1],1,[2]),[9] ┃ ┃ ┗ select([1],1,[]),[10] ┃ ┗ put([4,2],[1,3],[2,4,1,3]),[11] ┃ ┣ select([4,2],4,[2]),[12] ┃ ┗ put([2],[4,1,3],[2,4,1,3]),[13] ┃ ┗ select([2],2,[]),[14]>* 1: ┗ e_register(0,N1_10,N1_10+1) Try,[14] 1 Try : e_register(0,N1_10,N1_10+1) ?,F,fail,【使用可能局面】「Try」「Match」「Retry」,「Try」「Retry」において使われた場合には、表示されたゴールと単一化可能な頭部を持つ節の有無に関わらず直ちに失敗させます。,「Match」の場合には、表示された節も含めて、ゴールと単一化可能な頭部を持つ節は1つもなかったかのように動作します。,H,help,それぞれの局面で使用可能なコマンドの表をコンソールに出力します。,I,inspect,該当ゴールを含む節の定義に変数があり、その変数が束縛されている、または制約されているときその情報を表示します。,値が束縛された変数,定義側変数名  =  束縛された値,制約変数,定義側変数名  =  制約変数名 {領域制約リスト :: 遅延実行ゴール },なお、定義側変数が虚変数の場合、虚変数の出現順にシーケンシャル番号を付与し区別しています。,<例>,|?-listing.,turukame(Turu,Kame,Foot,Head) :-,Turu in 0..Head,,Kame in 0..Head,,Foot#=Turu*2+Kame*4,,Head#=Turu+Kame.,yes,|?-trace.,yes,||?-turukame(X,Y,14,5).,[1] 0 Try : turukame(X_7,Y_9,14,5) ?,Match : turukame(X_7,Y_9,14,5) :-,X_7 in 0..5,,Y_9 in 0..5,,14#=X_7*2+Y_9*4,,5#=X_7+Y_9.,[2] 1 Try : X_7 in 0..5 ? i,Foot = 14,Head = 5,[2] 1 Try : X_7 in 0..5 ?,<< BUILTIN CALL >>,[2] 1 Succ : _30 in 0..5,[2] 1 Try : Y_9 in 0..5 ? i,Turu = _30 { [0..5]::true },Foot = 14,Head = 5,[2] 1 Try : Y_9 in 0..5 ?,<< BUILTIN CALL >>,[2] 1 Succ : _46 in 0..5,[2] 1 Try : 14#=_30*2+_46*4 ? i,Turu = _30 { [0..5]::true },Kame = _46 { [0..5]::true },Foot = 14,Head = 5,[2] 1 Try : 14#=_30*2+_46*4 ?,<< BUILTIN CALL >>,[2] 1 Succ : 14#=_30*2+_46*4,[2] 1 Try : 5#=_30+_46 ? i,Turu = _30 { [1,3,5]::$clp_area_propagation(7,[1,2],[_30,_46]),! },Kame = _46 { [1..3]::$clp_area_propagation(7,[1,2],[_30,_46]),! },Foot = 14,Head = 5,[2] 1 Try : 5#=_30+_46 ?,<<BUILTIN CALL >>,[2] 1 Succ : 5#=3+2,<< LAST CALL >>,[1] 0 Succ : turukame(3,2,14,5),X = 3,,Y = 2,yes,J,jump,【使用可能局面】「Try」「Match」,「Try」のとき、この述語を実行せずに決定性成功をします。,「Match」のとき、この節のボディーゴールを実行せずに成功します。,L,leap,スパイまたはマーク(Sコマンド参照)がかかっているゴールに関する処理をインタプリタが行うまでデバッガの表示を打ち切ります。スパイまたはマークをかけた述語に関する情報のみを表示させたいときには連続してこのコマンドを使います。,N,notrace,トレースまたはスパイポイントを解除します。ただしデバッグモードは解除されません。,O,step return,親スタックにマークを付け「Lコマンド」の処理を実行します。トレース中にステップを追わなくてもよい節に入り込んでしまったときに使います。,P,parent,先祖である節をすべて表示します。,(節1の本体にあるゴールと、単一化可能な頭部を持つ節2をインタプリタが見つけ、その実行に取り掛かったとします。そのようなとき、節1は節2の親であると呼びます。親および親の親、そのまた親の親・・・・を先祖と呼びます。),<例>,| ?-[-'queen.pl'].,yes,| ?-spy select.,yes,debug mode on,||?-q(4).,[4] 3 Try : select([4,3,2,1],S_70,D_72) ? p,3: select([4,3,2,1],S_70,D_72),2: put([4,3,2,1],[],L_8) :-,*> select([4,3,2,1],S_70,D_72),,safe([],S_70,S_70),,put(D_72,[S_70],L_8).,1: queen(4,L_8) :-,generate(4,[4,3,2,1]),,*> put([4,3,2,1],[],L_8).,0: q(4) :-,e_register(0,0,0),,*> queen(4,L_8),,e_register(0,N1_10,N1_10+1),,M_12 is N1_10+1,,write('No.'),,write(M_12),,nl,,disp(L_8,4),,fail.,Goal: ?- q(4).,[4] 3 Try : select([4,3,2,1],S_70,D_72) ?,Q,mark&leap,【使用可能局面】「Try」「Retry」,スタックにマークを付け「Lコマンド」の処理を実行します。,R,redo,【使用可能局面】「Fail」,Failした該当ゴールを再Tryします。Failした原因を再検証したり、Breakしてプログラムを追加してから再実行させるなどの用途があります。,S,mark/unmark,【使用可能局面】「Try」「Retry」,スタックにマークを付けます。,既にマークがついているスタックではマークを削除します。,W,where,「Match」の場合には、Matchした述語定 義の位置(述語名/アリティ/マッチした節の順位)が表示されます。,Match以外の局面(Try,Retry,Succ,Fail,Pop)では、ゴールの位置(親述語名/親述語 アリティ/親述語の節順位/節中のゴール順位)が表示されます。,<例>,| a:- b.        % a/0/1  述語名=a,アリティ=0 ,第1節,| a:- c.         % a/0/2  述語名=a,アリティ=0 ,第2節,||?-a., [1] 0 Try   :a ?  ,  Match   : a :-,                b. ? w  ,      a/0/1      , [2] 1 Try   :b ? w     ,          a/0/1/1       ,6-5-3.Dコマンドを使ったスタック状態の調べかた,Prologの理解を深めるため、前節で説明したDコマンドを使って、スタックの状態を追ってみます。,<例1>次のようなシンプルなプログラムで説明します。,%%%%%%%%%%%%%%%,%% tree.pl %%,a:-b,c.     % b かつ c が真ならば、a は真である。,b:-d,e.     % d かつ e が真ならば、b は真である。,e:-f.      % f が真ならば、e は真である。,d.       % d は真である。,d.       % d は真である。(オルタナティブ。下図では d'で表現),f.       % f は真である。,f.       % f は真である。(オルタナティブ。下図では f'で表現),c.       % c は真である。,このプログラムで a が真か調べる過程は次のように木構造の成長で表現できます。,?-a.,=STEP1================,0:     [1]a Try,=STEP2================,0:     [1]a,       /,1:    [2]b Try,=STEP3================,0:     [1]a,       /,1:    [2]b ,      /,2: [3]d(d') Try = Succ,=STEP4================,0:     [1]a,       /,1:    [2]b,      ∧,2: [3]d(d') [4]e Try,=STEP5================,0:     [1]a,       /,1:    [2]b,      ∧,2: [3]d(d') [4]e,       /,3:    [5]f(f') Try = Succ,=STEP6================,0:     [1]a,       /,1:    [2]b,      ∧,2: [3]d(d') [4]e Succ,       /,3:    [5]f(f'),=STEP7================,0:     [1]a,       ∧,1:    [2]b [6]c Try,      ∧    ┃,2: [3]d(d') [4]e  ┃,       /    ┃バックトラック,3:    [5]f(f')┣━┛,=STEP8================,0:     [1]a,       /,1:    [2]b ,      ∧,2: [3]d(d') [4]e,       /,3:    [5]f' ReTry = Succ (オルタナティブがないのでスタックからPOPします),=STEP9================,0:     [1]a,       /,1:    [2]b ,      ∧,2: [3]d(d') [4]e Succ (オルタナティブがないのでスタックからPOPします),=STEP10================,0:     [1]a,       ∧,1:    [2]b [4]c Try = Succ (C/Rで次に進ませます),      /,2: [3]d(d'),=================,yes,ここで、,[数値]は「シリアルナンバー」(インタプリテーションが始まってからの実際のゴールの起動順番)、縦座標の”数値:”はその行のゴールの「先祖系列の深さ」です。,プログラムは[1]->[2]->[3]->[4]->[5]->[6]の順に働き、[6]c Tryで強制的にFailすると辿った道筋の逆順、[6]->[5]->[4]->[3]->[2]->[1]の順にバックトラックします。,これをトレース過程にDコマンドを織り込みながらスタック状態を調べてみましょう。,Dコマンドの出力は木構造をCUIで表現するために上記のGUI木構造を左右反転し「シリアルナンバー」順に並べ、親子関係を罫線文字で接続しています。,| ?-[-'tree.pl'].,yes,| ?-leash2(2),trace.,yes,debug mode on,||?-a.,[1] 0 Try : TopGoal :a ?,Match : a/0/1 :  ,a :-,b,,c.,[2] 1 Try : a/0/1/1 :b ?,Match : b/0/1 :   ,b :-,d,,e.,[3] 2 Try : b/0/1/1 :d ? d,[1] 0: a   ,[2] 1: ┗ b,[3]>* 2: ┗ d Try   ,[3] 2 Try : b/0/1/1 :d ?,Match : d/0/1 :   ,d.,[3] 2 Succ : b/0/1/1 :d    ,[4] 2 Try : b/0/1/2 :e ? d   ,[1] 0: a    ,[2] 1: ┗ b,[3] ┣ d,[4]>* 2: ┗ e Try   ,[4] 2 Try : b/0/1/2 :e ?,Match : e/0/1 :   ,e :-,f.,[5] 3 Try : e/0/1/1 :f ? d,[1] 0: a  ,[2] 1: ┗ b    ,[3] ┣ d,[4] 2: ┗ e,[5]>* 3: ┗ f Try   ,[5] 3 Try : e/0/1/1 :f ?    ,Match : f/0/1 :   ,f.,[5] 3 Succ : e/0/1/1 :f    ,[4] 2 Succ : b/0/1/2 :e    ,[2] 1 Succ : a/0/1/1 :b    ,[6] 1 Try : a/0/1/2 :c ? d  ,[1] 0: a,[2] ┣ b  ,[3] ┃ ┣ d  ,[4] ┃ ┗ e  ,[5] ┃ ┗ f  ,[6]>* 1: ┗ c Try   ,[6] 1 Try : a/0/1/2 :c ? f  ,[6] 1 Fail : a/0/1/2 :c  ,[5] 3 Pop : e/0/1/1 :f  ,[5] 3 Retry : e/0/1/1 :f ? d ,[1] 0: a,[2] 1: ┗ b,[3] ┣ d,[4] 2: ┗ e,[5]>* 3: ┗ f Retry  ,[5] 3 Retry : e/0/1/1 :f ?,Match : f/0/2 :,f.,[5] 3 Succ : e/0/1/1 :f,>   ,[4] 2 Succ : b/0/1/2 :e   ,[2] 1 Succ : a/0/1/1 :b    ,[4] 1 Try : a/0/1/2 :c ? d  ,[1] 0: a,[2] ┣ b,[3] ┃ ┗ d,[4]>* 1: ┗ c Try,[4] 1 Try : a/0/1/2 :c ?    ,Match : c/0/1 :    ,c.,[4] 1 Succ : a/0/1/2 :c,[1] 0 Succ : TopGoal :a,yes,<例2>,次にもう少し具体的な例を見てみましょう。,1)バックトラックは「シリアルナンバー」を逆に辿ること、すなわち辿ってきた道筋を戻ることであるのを確認してください。,2)もともとオルタナティブがない組込述語(is/2など)ユーザー定義述語、再試行後にオルタナティブがなくなり決定性終了をしたユーザ定義述語はスタックに積まれない(バックトラックの対象から除かれる)ことを確認してください。,%%%%%%%%%%%%%,%% cost.pl %%,購入総額(Yen,[S|Summary]) :- % 購入総額は商品代金+送料である,商品代金(Goods,Summary),,送料(Send,S),,Yen is Goods+Send.,商品代金(Price+Cost,[Package,Grade]) :- % 商品代金は商品価格+梱包費である,商品価格(Price,Grade),,梱包費(Cost,Package).,梱包費(Cost,Package) :- % 梱包費は梱包材費用のことである,包装材費用(Cost,Package).,商品価格(1000,傷あり特価品). % 商品は2種類ある,商品価格(4000,特選最上級品).,包装材費用(0, 新聞紙袋簡易包装). % 包装材は2種類ある,包装材費用(100, ダンボール箱梱包).,送料(120,普通便). % 送料は2種類ある,送料(340,速達便).,yes,| ?-[-'cost.pl'].,yes,| ?-leash(trs),trace.,yes,debug mode on,||?-購入総額(Yen,S).,[1] 0 Try : 購入総額(Yen_5,S_7) ?,Match : 購入総額(Yen_5,[S_11|Summary_13]) :-,商品代金(Goods_15,Summary_13),,送料(Send_17,S_11),,Yen_5 is Goods_15+Send_17.,[2] 1 Try : 商品代金(Goods_15,Summary_13) ? d,[1] 0: 購入総額(Yen_5,[S_11|Summary_13]),[2]>* 1: ┗ 商品代金(Goods_15,Summary_13) Try,[2] 1 Try : 商品代金(Goods_15,Summary_13) ?,Match : 商品代金(Price_21+Cost_23,[Package_25,Grade_27]) :-,商品価格(Price_21,Grade_27),,梱包費(Cost_23,Package_25).,[3] 2 Try : 商品価格(Price_21,Grade_27) ? d,[1] 0: 購入総額(Yen_5,[S_11,Package_25,Grade_27]),[2] 1: ┗ 商品代金(Price_21+Cost_23,[Package_25,Grade_27]),[3]>* 2: ┗ 商品価格(Price_21,Grade_27) Try,[3] 2 Try : 商品価格(Price_21,Grade_27) ?,Match : 商品価格(1000,傷あり特価品).,[3] 2 Succ : 商品価格(1000,傷あり特価品) ?,[4] 2 Try : 梱包費(Cost_23,Package_25) ? d,[1] 0: 購入総額(Yen_5,[S_11,Package_25,傷あり特価品]),[2] 1: ┗ 商品代金(1000+Cost_23,[Package_25,傷あり特価品]),[3] ┣ 商品価格(1000,傷あり特価品),[4]>* 2: ┗ 梱包費(Cost_23,Package_25) Try,[4] 2 Try : 梱包費(Cost_23,Package_25) ?,Match : 梱包費(Cost_23,Package_25) :-,包装材費用(Cost_23,Package_25).,[5] 3 Try : 包装材費用(Cost_23,Package_25) ? d,[1] 0: 購入総額(Yen_5,[S_11,Package_25,傷あり特価品]),[2] 1: ┗ 商品代金(1000+Cost_23,[Package_25,傷あり特価品]),[3] ┣ 商品価格(1000,傷あり特価品),[4] 2: ┗ 梱包費(Cost_23,Package_25),[5]>* 3: ┗ 包装材費用(Cost_23,Package_25) Try,[5] 3 Try : 包装材費用(Cost_23,Package_25) ?,Match : 包装材費用(0,新聞紙袋簡易包装).,[5] 3 Succ : 包装材費用(0,新聞紙袋簡易包装) ?,[4] 2 Succ : 梱包費(0,新聞紙袋簡易包装) ?,[2] 1 Succ : 商品代金(1000+0,[新聞紙袋簡易包装,傷あり特価品]) ?,[6] 1 Try : 送料(Send_17,S_11) ? d,[1] 0: 購入総額(Yen_5,[S_11,新聞紙袋簡易包装,傷あり特価品]),[2] ┣ 商品代金(1000+0,[新聞紙袋簡易包装,傷あり特価品]),[3] ┃ ┣ 商品価格(1000,傷あり特価品),[4] ┃ ┗ 梱包費(0,新聞紙袋簡易包装),[5] ┃ ┗ 包装材費用(0,新聞紙袋簡易包装),[6]>* 1: ┗ 送料(Send_17,S_11) Try,[6] 1 Try : 送料(Send_17,S_11) ?,Match : 送料(120,普通便).,[6] 1 Succ : 送料(120,普通便) ? d,[1] 0: 購入総額(Yen_5,[普通便,新聞紙袋簡易包装,傷あり特価品]),[2] ┣ 商品代金(1000+0,[新聞紙袋簡易包装,傷あり特価品]),[3] ┃ ┣ 商品価格(1000,傷あり特価品),[4] ┃ ┗ 梱包費(0,新聞紙袋簡易包装),[5] ┃ ┗ 包装材費用(0,新聞紙袋簡易包装),[6]>* 1: ┗ 送料(120,普通便) Succ,[6] 1 Succ : 送料(120,普通便) ?,[7] 1 Try : Yen_5 is 1000+0+120 ?,>,[7] 1 Succ : 1120 is 1000+0+120 ? d,[1] 0: 購入総額(1120,[普通便,新聞紙袋簡易包装,傷あり特価品]),[2] ┣ 商品代金(1000+0,[新聞紙袋簡易包装,傷あり特価品]),[3] ┃ ┣ 商品価格(1000,傷あり特価品),[4] ┃ ┗ 梱包費(0,新聞紙袋簡易包装),[5] ┃ ┗ 包装材費用(0,新聞紙袋簡易包装),[6] ┣ 送料(120,普通便),[7]>* 1: ┗ 1120 is 1000+0+120 Succ,[7] 1 Succ : 1120 is 1000+0+120 ?,[1] 0 Succ : 購入総額(1120,[普通便,新聞紙袋簡易包装,傷あり特価品]) ?,Yen = 1120,                     ,S = [普通便,新聞紙袋簡易包装,傷あり特価品];    ,[6] 1 Pop : 送料(120,普通便)           ,[6] 1 Retry : 送料(Send_17,S_11) ?          ,Match : 送料(340,速達便).            ,[6] 1 Succ : 送料(340,速達便) ?,[6] 1 Try : Yen_5 is 1000+0+340 ?,>,[6] 1 Succ : 1340 is 1000+0+340 ? d,[1] 0: 購入総額(Yen_5,[速達便,新聞紙袋簡易包装,傷あり特価品]),[2] ┣ 商品代金(1000+0,[新聞紙袋簡易包装,傷あり特価品]),[3] ┃ ┣ 商品価格(1000,傷あり特価品),[4] ┃ ┗ 梱包費(0,新聞紙袋簡易包装),[5] ┃ ┗ 包装材費用(0,新聞紙袋簡易包装),[6]>* 1: ┗ Yen_5 is 1000+0+340 Try      ,[6] 1 Try : Yen_5 is 1000+0+340 ?,[1] 0 Succ : 購入総額(1340,[速達便,新聞紙袋簡易包装,傷あり特価品]) ?,Yen = 1340,                     ,S = [速達便,新聞紙袋簡易包装,傷あり特価品],yes,%% 第2解が求まった後、再度別解要求をすると包装材費用の別可能性を試行します,%% 次のような問い合わせをするとどのようなTraceになるか試し、なぜそうなるのか考えてください,||?-購入総額(Yen,[速達便,X,特選最上級品])."}); htmllist.push({"file":"manuals/manual_compiler.html#compiler","title":"7-1.はじめに","text":"7-1.はじめに,【Windows版AZ-Prologをお使いの方へ】,「7-2.AZ-Prologコンパイラの概要」で説明していますが、Prologで記述したプログラムの実行モジュールを生成(これをフルコンパイルと呼びます)する場合は、Cコンパイラが必要になります(バイトコードコンパイル(7-2-1参照)のみ利用する場合は不要です)。,Linux版の場合はOS標準のgccを使用しますので特に必要ありませんが、Windows版をお使いの方は、Prologコンパイラを使用する前にCコンパイラをまずインストールします。,「Visual Studio Community」が以下URLから無償で入手できますので、 手順にしたがってインストールしてください。,VS2017のDownLoad:https://www.visualstudio.com/vs/community/,VS2013、2015を既にお使いでライブラリなどをVS2017に更新できないお客様はVS2013用またはVS2015用のAZ-Prologをダウンロードしてください。インストールする際に「c++によるデスクトップ開発」にチェックを入れてください。,C:¥ProgramData¥Microsoft¥Windows¥Start Menu¥Programs¥Visual Studio 2017¥Visual Studio Tools¥VC から「x86 Native Tools Command Prompt for VS 2017」(32ビット)「x64 Native Tools Command Prompt for VS 2017」(64ビット)を開いてコンパイルすることになるので、インストール後にデスクトップにショートカットを作成しておくと便利です。プロパティの「作業フォルダ」も自分用に変更しておきましょう。,Mac版をお使いの方は、デフォルトではCコンパイラがインストールされていませんので、以下の手順でソフトウェア開発環境を整えます。なお、既にCコンパイラ(gcc,g++)が利用できる場合は下記の作業は必要ありません。,AppleサイトよりXcodeをダウンロードしインストールを行う。(GUIベースのインストール),コマンドラインツールのインストール,ターミナルを開き、以下のコマンドを入力する,$ xcode-select --install,MacPortsのインストール,3-1.,MacPortsサイト(http://www.macports.org)よりPackageをダウンロードする。サイト上で[Mac OS X Package (.pkg) Installer]の該当OSバージョン(v10.9以上)をクリックする。,3-2.,Packageのインストールを行う。ダウンロードしたパッケージ(*.pkg)をダブルクリックしMacPortsインストーラーを起動させ、画面に従い必要な情報を入力し、インストールを実行する。,ターミナルを開き、以下のコマンドを入力してソフトウェア及びライブラリ関連の更新を行う。,$ sudo port selfupdate,$ sudo port install cmake,$ sudo port install nkf"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_2","title":"7-2.AZ-Prologコンパイラの概要","text":"7-2.AZ-Prologコンパイラの概要,AZ-Prologコンパイラ(Windows版ではazpc.exe、Linux版またはMac版ではazpc)は、prologで書かれたプログラムを高速で実行したり、実行モジュール(プログラム)を生成したりする目的で使用します。,コンパイラは、インタプリタの一部として組み込まれたシステムではなく、独立したコマンドとして提供されます。,AZ-Prologで提供される各種Prologインタプリタ(標準、CGI用、子プロセス用)は、実はコンパイラによって生成されたものです。,ちなみに、AZ-Prologコンパイラは、Prologで記述されたソースプログラムを自分自身でコンパイルして生成された実行プログラムです。,AZ-Prologコンパイラは、コンパイルオプションの指定で次の2種類のいずれかのコードを出力します。,1) インタープリティブ・バイトコード,2) C言語のソースコード,前者については7-2-1で、後者については7-2-2で、それぞれの概要を説明しています。また、それぞれのコンパイルオプションの処理イメージを表した図を7-2-3で示しています。,7-2-1.インタプリティブバイトコード,インタプリタから直接ロードして実行可能なコードです。,インタプリタに内蔵されているバイトコードエミュレーターが解釈実行します。,バイトコードとは、フルコンパイルイメージのエミュレーションコード(Abstract Machine Code)で、WAM(Warren Abstract Machine)に近いコード体系です。詳細についての説明は省略します。,プログラムをバイトコード化する事で、通常の(「consult」や「restore」により読み込まれた)コードでの実行速度より4倍程度の高速化と領域節約が計れます。,このコンパイルではCコンパイラを必要としません。,7-2-2.C言語のソースコード(フルコンパイル時),フルコンパイルでは、AZ-PrologコンパイラはC言語のソースコードを出力し、Cコンパイラにより機械語オブジェクトを生成してリンカで結合して実行モジュールを作ります。,これによりインタプリタでの通常コードの実行よりも、10倍前後高速化する事が出来ます。,このフルコンパイルは、主に次の目的で使われます。,Prologで記述された述語を組込述語にコンパイル(これを「コンパイル組込述語」と呼びます)し、それを追加した新しいProlog拡張インタプリタを生成する。,ユーザが作成したプログラムのスタンドアロンアプリケーション(単独実行プログラム:以下では単に「実行プログラム」と呼んでいます)を生成する。,2.の場合、インタプリタとして使うことはできませんが、「インタプリタコードの読み込み機能」(consult/reconsultはなくても、その省略記法は有効:「7-4.(10)ファイルのインクルード」参照)、「トップレベルの述語呼び出し機能」(7-4.(11)top_level述語の定義」参照)は確保されています。また、組込述語はリンクされませんが、必要な述語は、明示的に宣言(「7-4.(6)bltin宣言」参照)すれば組込むことができます。,1、2のいずれの場合も、述語やプログラムの記述は主にPrologのソースコードですが、所定の形式を踏まえたC言語のソースコードでも記述可能です。Prologのソースコードから生成されたCソースや、最初からC言語で記述されたCソースは、Cコンパイラでコンパイルされ、リンカでAZ-Prologの組込述語ライブラリ・Cコンパイラ標準関数ライブラリ等とリンクされることにより、実行可能なプログラムが生成されます。,言うまでもありませんが、AZ-Prologフルコンパイラが生成したCソースは、テキストエディタで修正・編集することが可能ですし、ユーザが作成したCプログラムとオブジェクトレベルでのリンクも可能です。,7-2-3.AZ-Prologコンパイラの機能フローイメージ,バイトコードコンパイラとインタプリタの機能相関図,AZ-Prologフルコンパイルの処理イメージ"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_3","title":"7-3.コンパイル前の諸注意","text":"7-3.コンパイル前の諸注意,AZ-Prologコンパイラでは、コンパイル対象のファイルやコンパイラに対する指示をコマンドラインに指定して起動します。これによりエラーがなければ目的のファイルが生成されるわけですが、この時下表のようなファイルも中間ファイルとして生成されます。ファイル名の付け方によっては同名の既存ファイルが破壊される恐れがありますので注意が必要です。,ファイル拡張子「.c」「.obj」はCコンパイラが使用しますし、これら以外にもシステムで使われているもの(「.dll」等))がありますので、特にPrologソースファイル名はそれらと衝突しないように注意してください(実はAZ-Prologには拡張子の制約はありません。でも、Prologソースファイル拡張子は「.pl」とするのが一般的です)。,PrologソースをCソースヘ変換する際、新しいファイル名は拡張子を削除して「.c」を付加したものとなりますので、拡張子のみでソースを区別するようなファイル名の付け方は避けてください。,コンパイルはファイル単位で行われますが、module宣言(7-4.(1)参照)がされている場合はモジュール毎に分割されます。この場合、生成ファイル名は「モジュール名.c」となります。,★コンパイル中に作成される中間ファイル,1.Cソース,xxx.pl→xxx.c(モジュール名.c),2.objectファイル,xxx.c→xxx.o(モジュール名.obj),3.Cコンパイラ起動用,mkazまたはmkaz.cmdバッチファイル,4.リンクファイル,userfile.c,これらの中間ファイルは、全てカレントディレクトリに作成されます。,【注意】,フルコンパイルには、Cコンパイラがインストールされていなければなりません。"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_4","title":"7-4.ソースファイルに対する追加記述","text":"7-4.ソースファイルに対する追加記述,インタプリタ上でデバッグの済んだソースプログラムをコンパイルし、新しいPrologインタプリタや実行プログラムを生成する際に、ソースファイルに必要に応じて追加記述をしなければならないものがあります。これらを初めからソースに書いておいてインタプリタでデバッグをしても、まったく支障ありません。,★コマンドで与えるもの,行頭を「:-」で始め、コンパイラに対する宣言や実行時の指示を行います。,(インタプリタでファイルを読み込んだ場合は無視されます。),(1) module宣言,ファイルのモジュール分割を宣言します。,(2) public宣言,組込述語に登録する述語を宣言します。,(3) publicall宣言,全述語をpublic宣言します。,(4) extern宣言,外部定義述語の参照を宣言します。,(5) mode宣言,述語引数の入出力区分、型宣言をします。,(6) bltin宣言,リンクする組込述語を宣言します。,(7) dynamic 宣言,assert/retractの対象述語を宣言します。,(8) オペレータ宣言,コンパイル時オペレータを宣言します。,(9) 実行時オペレータ宣言,実行時オペレータを宣言します。,(10) 他ファイルのインクルード ,実行時のファイルの読み込みを指示します。,拡張インタプリタを生成する際には、1ファイル(宣言がされていれば、1モジュール)に最低1個のpublic宣言がされている必要があります。,★述語の形式で記述するもの,述語名/アリティの述語の定義を与えると言う意味です。,インタプリタで読み込んでも、述語が定義されるだけで、呼び出されはしません。,(11) top_level/0,トップレベル述語の定義を与えます。,単独実行プログラムを作成する時は、起動直後に制御を移される「top_level/0」 の定義をしておきます。定義がないときはAZ-Prolog側で用意されている「top_level」がリンクされます。これはインタプリタとして起動するためのものです。つまり、単独実行プログラム(コンパイラオプション「/i」の指定なし)でありながらtop_level/0を定義しないと、組込述語も使えないPrologインタプリタが起動されることになります。,以下、(1)から(11)まで順に説明していきます。,(1) module宣言,【書 式】,:-module モジュール名.,・・・・・・①,:-module モジュール名/compact.,・・・・・・②,:-module モジュール名/fast.,・・・・・・③,【機 能】,ファイルをモジュールに分割するのに用います。この宣言は新たなモジュールの開始を意味します。次のmodule宣言が現れるか、ファイルの最後に到達すれば、それがこのモジュールの範囲になります。コンパイラはPrologソースファイルをモジュールに分割し、各モジュール名をつけたCソースファイルを生成します。,module宣言の無いファイル、または最初のmodule宣言の前に述語定義が有る場合は、ファイル名がモジュール名として扱われます。,モジュール名はC言語の関数名として妥当なものでなければなりません。(なぜなら、コンパイラはモジュール名をそのまま関数名の一部として使って、初期化関数(モジュールに含まれる組込述語を登録するための関数)を自動的に定義するからです。),【説 明】,書式①,コンパイルの優先指定はデフォルト値(速度/fast、③と同じ)が採用されます。,書式②,生成するコードのサイズ縮小を優先してコンパイルします。,書式③,生成するコードの実行速度向上を優先してコンパイルします。,生成コードのサイズ縮小/実行速度向上いずれを優先するかは、コンパイル指示コマンド(azpcのコマンドラインの-p以降のオプション)により与えることもできます((「7-5.コンパイラの起動時のオプション」の「Prologコンパイルの形式、モードの指定」参照)。指示コマンドが無い場合はサイズ優先となります。,【記述例】,(ファイル名) myfile.pl,mifile.c,:-module my1/fast.,my1.c(速度優先),:-module my2/compact.,my2.c(サイズ優先),(2) public宣言,【書 式】,:-public 述語名/アリティ.,:-public invisible:述語名/アリティ.,【機 能】,モジュール中に定義が記述されている「述語名/アリティ」の述語を、組込述語として登録することを指示します。,【説 明】,public宣言には次のような目的があります。,①,public宣言された述語を、他のモジュールからも呼べるようにします。,コンパイルした時、この述語はC言語のpublic関数に変換されます。これにより、他のモジュールでこの述語をextern宣言すれば呼び出せる状態になります。,逆に、public宣言されていない述語はC言語のstatic関数に変換されます。あるモジュールの中だけで呼ばれ、他のモジュールからは呼ばれない述語はpublic宣言しません。それにより、モジュール間の述語名の衝突などを回避することができます。,②,public宣言された述語を組込述語として登録します。,これにより、インタプリタとして起動した時、トップレベルから呼び出すことが可能になります。登録された述語は自動的にextern宣言されます。,invisible指定を付加した場合は、組込述語としての登録をしません。つまり、①だけが行われることになります。この状態では、インタプリタとして起動した場合、それらの述語は見えません。単独実行プログラムとして動作させる場合は、他のモジュールからもその述語を呼び出すことができます。但し、そのためには呼び出し側のモジュールで同述語をextern宣言する必要があります。,invisible指定なしの通常のpublic宣言では、①に加えて②も行われます。即ち、インタプリタのトップレベルから呼び出すことができます。,【記述例】,:-public my_append/3.,my_append([],L,L).,my_append([A|L],B,[A|BL]):-,my_append(L,B,LB).,:-extern my_append/3.,reverse([],[]).,reverse([A|B],C):-,reverse(B,D),,my_append(D,[A],C).,【諸注意】,public宣言がされると、その述語はコンパイルリンクする全ファイルから見えますので、同一述語名が複数のファイルでpublic宣言されているとリンク時エラーとなります。,暗黙のpublic宣言:「 top_level/0 」述語の定義もpublic宣言された述語もないソースファイルは、publicall宣言されたものと見なされます。,(3) publicall宣言,【書 式】,:-publicall.,【機 能】,モジュール中に定義されている全ての述語を public 宣言します。,主に、デバッグ時に各々の述語を単体で実行してテストするときなどに使います。,暗黙のpublic宣言:「 top_level/0 」述語の定義もpublic宣言された述語もないソースファイルは、publicall宣言されたものと見なされます。,(4) extern宣言,【書 式】,:-extern 述語/アリティ.,:-extern det:述語/アリティ.,:-extern c:述語/アリティ.,【機 能】,他のモジュールで定義されpublic宣言された述語を、自分のモジュールの中で使うことを宣言します。,【説 明】,コンパイルはモジュール単位に行われます。,同一モジュールに定義されていない述語が呼び出されている場合、それが他のモジュールにある述語なのか、インタプリタコード(実行時にPrologソースをコンサルトする中間言語形式)の述語なのか、コンパイラにはわかりません。extern宣言は、その述語が他モジュールに存在し、コンパイル・リンク可能であることをazpcコンパイラに知らせます。,その場合、述語呼び出しは直接関数呼び出し(C言語レベル)コードに変換されますので、高速になります。,public宣言されている述語であれば、extern宣言をしていなくても、インタプリタコードと同様に呼び出すことはできますが、コンパイル時に組込述語 「call/1」(に相当するC言語の関数)を介した呼び出しコードに変換されますので、直接関数呼び出しより処理効率は落ちます。,extern宣言を行ない、他モジュールでpublic宣言されていなければリンク時にエラーとなります。但し、宣言のみしていて使用していなければ問題はありません。,extern宣言をしていても、自分のモジュール中に同一の述語がある場合は単に無視します。,なお、標準組込述語はすべてextern宣言されています。,「det:」指定を付加すると、決定性述語としてコンパイルされた外部述語であることを宣言し呼び出し、実行が高速化されます。指定しない場合は非決定性述語と見なされ、バックトラック可能な構造の関数に変換されますが、「det:」指定によりこの部分が簡略化されるためです。,「c:」指定は、この述語が実際は直接C言語で書かれたint型の関数であることを示します。C言語で定義された関数がなければ、リンク時にエラーになります。これに関しては、「8-2-3.各関数の定義 (B)テンプレート出力の利用」を参照してください。,(5) mode宣言,【書 式】,:-mode 述語名(引数のモード並び).,引数のモード,+,入力引数(値をもって呼ばれます)。,-,出力引数(変数で呼ばれます)。,?,両用引数。,float,入力引数であり、実数型が必ず渡されます。,integer,入力引数であり、整数型が必ず渡されます。,atom,入力引数であり、アトム型が必ず渡されます。,number,入力引数であり、整数または実数が必ず渡されます。,list,入力引数であり、リスト型が必ず渡されます。,cterm,入力引数であり、複合項が必ず渡されます。,【機 能】,コンパイラの最適化のための指示です。,モード指定と異なった使われ方をした場合、結果は保証されません。,一般に細かく指定することにより高速化されます。,引数の入出力指定と型指定を同時に行うことはできません。後の宣言が優先されます。,【記述例】,:-mode my_append(+,+,-).,:-mode safe(list,integer,integer).,(6) bltin宣言,【書 式】,:-bltin 述語名/アリティ.,【機 能】,実行するプログラムに指定の組込述語をリンクする事を明示します。,【説 明】,コンパイル時に/iオプションが付いている場合は、この宣言は不要です。/iが付かない場合でも、ソースコード中で陽に組込述語が呼ばれている場合は、コンパイラが組込述語呼び出しのC言語ソースコードに変換してくれるので、やはりその組込述語のbltin宣言は不要です。,只、ある組込述語の呼び出し形式の項が変数にバインドされ、この変数が組込述語call/1に引数として渡される場合は、コンパイラは組込述語の呼び出しであることが判断できません。そのような場合にこの宣言を用います。,【記述例】,:-bltin read/1.,(7) dynamic宣言,【書 式】,:-dynamic 述語名/アリティ.,【機 能】,述語をコンパイルせず、インタプリタコードのままとします。,【説 明】,「assert」「retract」を前提とした述語の初期値(下の記述例参照)をソースに記述したい場合などに用います。,コンパイルした拡張インタプリタを起動して、「listing/0 」を実行してみると、dynamic宣言した述語だけが表示されます。,暗黙のdynamic宣言:ソースコード解析時に「retract」「clause」など、項として取り扱っている述語は暗黙でシステムがdynamic宣言します。,【記述例】,:-dynamic counter/1.,counter(0).,(8) オペレータ宣言,【書 式】,:-op(強さ,型,アトム).,【機 能】,コンパイル時のオペレータを宣言します。,【説 明】,コンパイルされた実行プログラムでは、このオペレータ宣言は無効です。逆に、インタプリタでコンサルトした場合は、このオペレータ宣言は有効になります。,【記述例】,:-op(600,fx,#).,(9) 実行時オペレータ宣言,【書 式】,:-run:op(強さ,型,アトム).,【機 能】,実行時のオペレータを宣言します。,【説 明】,この宣言は、コンパイル時に使用するオペレータではなく、コンパイルされた実行プログラムが使用するオペレータを宣言します。,【記述例】,:-run:op(600,fx,#).,(10) ファイルのインクルード,【書 式】,:-[ファイル名].,【機 能】,ファイルの内容を取り込みます。,【説 明】,ファイル名はシングルクォート「'」で囲ったアトムで指定します。,リコンサルト指定(-ファイル名)であっても、コンサルトと同様に扱います。,インクルードされるファイルにmodule宣言が含まれていても、それを無視して現在コンパイル中のモジュールと一体化します。,(11) top_level述語の定義,【書 式】,top_level :- ゴール並び.,【機 能】,コンパイル・リンクされた実行ファイルのトップレベル述語(そのファイルの起動後に直ちに呼び出される述語)を定義します。,【説 明】,コンパイルされたファイルに「 top_level/0 」の定義があると、コンパイラはAZ-Prolog本来のトップレベル述語(インタプリタを起動する)をリンクせずに、この述語と置き換えます。従って、実行プログラムの起動用述語として使います。,「 top_level/0 」の定義は、当然のことながらリンクする全ファイル中で一つだけでないとリンクエラーとなります。,「 top_level/0 」は自動的にpublic宣言されるので、改めてpublic宣言する必要はありません。,「 top_level/0 」が成功または失敗すると、プログラム自体が終了し、OSレベルに戻ります。,実行プログラムが無限ループに入ると、終了できなくなりますので注意してください(インタプリタのようにCTRL-Cでは割り込めません)。以下は、その無限ループに入る例です。,【記述例】,top_level:-repeat,fail."}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_5","title":"7-5.コンパイラの起動時のオプション","text":"7-5.コンパイラの起動時のオプション,AZ-Prologコンパイラは、コマンドラインのオプションにより、コンパイルするファイルを指定したり、コンパイラに対する各種指示ができるようになっています。,<例:lisp.plをコンパイルしてlisp (.exe)を生成する場合>,C:¥>azpc -p lisp.pl /e lisp,コマンドラインオプションの指定方法は、凡そ以下の通りです。,C:¥>azpc ・・・・(A)・・・・ -p ・・・・(B)・・・・,↑ ↑,コンパイラ自身が コンパイラへの,使用する領域のサイズ指定 ファイル指定、各種指示,コマンド azpc と「-p」オプションに挟まれた部分(A)には、コンパイラが実行時に使用するワークエリアのサイズを指定します(省略可能)。また、-pの後に続く行末までの(B)の部分には、コンパイル対象のファイルやコンパイラへの各種指示等を指定します。,以下でA、Bの各部分で指定するオプションについて解説します。,A.コンパイラワークエリア指定,ここで指定するオプションはインタプリタ起動時のワークエリアのサイズ指定と同じです。,通常はデフォルト(指定なし)で十分ですが、大きなPrologプログラム(極端に長いゴール列や引数中の構造体が複雑な場合など)をコンパイルすると、スタック不足、ヒープ不足(7-9.コンパイル時のエラー参照)が生じることがあります。このような時に指定してください。,【書 式】,[-h xx] [-l xx] [-g xx] [-a xx],xxはセル数を表す数値(キロ単位)。鍵カッコは各オプションが省略可能であることを表します。,各オプションの意味は以下の通りです。,-h ヒープ領域,-l ローカルスタック,-g グローバルスタック,-a アトム領域,ここで指定するオプションはインタプリタ起動時の指定と同じです。詳細はインタプリタの起動時オプションをご覧ください(「3-3-1.ワークエリアのサイズ指定」)。,現在のコンパイラのワークエリアサイズ設定については、azpcを引数なしで実行した時に表示されるヘルプ情報の最後にある以下の情報から知ることができます。, ,== NOW WORK AREA SIZE SETTINGS ===,Atom Area 2000 K-Cells,Heap Area 2048 K-Cells,Local Stack 1024 K-Cells,Global Stack 2048 K-Cells,B.コンパイラへの各種指示,ここで指定するオプションには以下のものがあります。,(1) コンパイルファイル並び,(2) Prologコンパイルの形式、モードの指定,(3) 実行ファイル関係の指定,(4) Cコンパイラへの指示オプション,(5) リンカへの指示オプション,(6) その他コンパイラへの指示,以下、順に説明します。,(1) コンパイルファイル並び,以下のファイル名をスペースで区切って並べます。,・Cソースファイル(拡張子.c),Cコンパイラでコンパイルされ、リンクされます。,・オブジェクトファイル(Cコンパイル済のファイル)(拡張子.objまたは.o),単にリンクされます。,・Prologソースファイル(それ以外の任意の拡張子。通常は.pl),Cソースへの変換を行った上で、Cコンパイル、リンクされます。,(2) Prologコンパイルの形式、モードの指定,/byte,Prologソースをインタプリティブバイトコードにコンパイルする。,/bytecode,PrologソースをCソースバイトコード(注1)にコンパイルする。,/compact,Prologソースをサイズ優先Cソースにコンパイルする(注2)。,/fast,Prologソースを実行速度優先Cソースにコンパイルします。,/no_module,Prologソース中のmodule宣言を無視させる。,/debug,変換された述語のCソース関数にtraceでステップされるコードを挿入する(注3)。,注1:,Cソースバイトコード,Cソースの中にバイトコード(/byteと同様)が埋め込まれまれてコンパイルされます。実行時にはこのバイトコードをバイトコードインタプリタが解釈実行するので、フルコンパイルに比べて遅くなりますが、サイズはよりコンパクトになります。,注2:,module宣言での指定の方が優先します。,注3:,"[C]Try ....."と表示され、その都度コマンド入力待ちになります。,コンパイルコードからインタプリタコードを呼び出すような処理があり、このインタプリタコードのトレースを行いたい場合にも指定してください。,(3) 実行ファイル関係の指定,/clp_macro,ソースファイルにCLPマクロ記述があった場合、これを展開してコンパイルします。,9-3-2.制約論理 組込述語 A(12)決定性述語: macro_consult/1を参照,/curses,画面制御を可能にします。,/dcurses,画面制御を不可能にします(「/i」指定時のコンソールアプリ生成)。,/e ファイル名,生成する実行ファイル名を指定します。デフォルトは「prolog(.exe)」。,/fs_mode0,defaultの素性構造モード(fs_mode=1)で不具合のある場合、素性構造を取り扱わないモードでコンパイルします。,/i,全ての標準組込述語、デバッガを実行プログラムにとりこみます。,/cursesも暗黙で同時指定されます(不要時は「/dcurses」を明示してください)。,拡張インタプリタを生成する場合は、このオプションを指定してください。,/no,生成される実行プログラムの起動時のワークエリア指定を行えないように指定します。,これにより、起動時の引数エリアがすべてパラメータとなります。,起動ディレクトリに「prolog.def」ファイル(「3-3-7.ワークエリアオプション設定ファイル」参照)があれば、これを読込み設定します。「prolog.def」で定義された4個の数値は、「/h /l /g /a」へ割り当てられます。,/noclp,コンパイルする述語に制約変数のチェック・動作を含めません。(処理速度が向上します),/no_exlib,標準で組み込まれるコンパイル組込述語(7-6コンパイル組込述語)の組込をおこないません。,/no_ole,OLEオートメーション機能を使わないよう指示します(Windows版のみ)。,/h xx /l xx /g xx,/a xx /s xx,実行ファイルのデフォルトワークエリアの設定。,「heap」「local」「global」「atom」「stack」,※「/s」はマシンスタックサイズ(Kbyte単位)です。デフォルトではlocalスタックと連動したサイズを自動設定します。,※「/s」はWindows版のみ有効です。,(4) Cコンパイラ関連の指示オプション,/cc コンパイラ名,Cコンパイラを指定。,/ccopt 文字列,Cコンパイラに渡すオプションを指定(全ファイルに適用)。,/ccopt_only 文字列 Cソース名,指定Cソースのコンパイル時のみのオプションを指定。,(5) リンカ関連の指示オプション,/lib ライブラリ,基本ライブラリ以外のライブラリ指定。,/linker リンカ名,リンカを指定。,/link_opt 文字列,リンカの出力ファイル指定子を定義。,/link_opt2 文字列,リンカに渡すオプションを指定。,/link_lib ライブラリ,基本ライブラリの代替ライブラリ指定。,/static,静的リンク形式の実行モジュールを生成する場合に指定。,AZ-Prologの静的ライブラリ(Linux版はlibazp.a、Windows版はazp.lib )がリンクされる。, >azpc -p myprogram.pl /i /e myprolog /static,この形式に拡張機能を組み込む場合は、必要なソースファイルおよび静的ライブラリをコマンドラインに更に指定する(9章拡張機能概要の「9-1-5.拡張機能のスタティックリンク方法」を参照)。prologソース中のdlib_require/1 による動的ライブラリの読み込みはできない。,(6) その他コンパイラへの指示,/lint,コンパイル結果を生成せずにプログラムチェックします。,/f ファイル名,{ファイル・パラメータ・指示並び}を記述したファイルを読込む(7-11参照)。,/env ファイル名,Cコンパイル、リンクに先立ち実行されるバッチ等を指定。,Cコンパイラ等の環境設定バッチを用意しこれを指定する。,/log,コンパイル過程を「azpc.log」という名前のLogファイルに残します。,/message,コンパイル過程のメッセージを出力しない。,/no_mkaz,Prologコンパイルのみ。Cコンパイル・リンク用バッチ(mkaz)を生成しない。,/ncc,Prologコンパイルとバッチ生成のみ。Cコンパイルリンクをしない。,/NOM,「/no_mkaz」と「/message」をあわせた指示。,#define 文字列=値,文字列を宣言し、値を設定する。文字列は大小文字を区別しない。,#define 文字列,文字列を宣言し、値は空値とする。,#ifdef 文字列,文字列がそれまでに宣言されていれば、「#else」または「#endif」 が現れるまで,が有効。入れ子構造も可。,#else,「#ifdef」 の文字列が宣言されていなければ有効。,#endif,「#ifdef」ブロックを終了する。,$(文字列),文字列の環境変数または宣言文字列の値で置換。,以上のオプションについては特に並びの順番は問いません。,<例>,C:¥>azpc -p mypro.pl myfile.c myold.obj /e myprolog /i,C:¥>azpc -h 5 -p #define Type1 /f prologmake.txt"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_6","title":"7-6.その他諸注意","text":"7-6.その他諸注意,コンパイラに対する生成コードの速度優先/サイズ優先指定は、起動時のオプションより、ソースコードに記述したmodule宣言での指定が優先されます。module宣言そのものを無視するオプション「/no_module」と併用することによって、コンパイルファイル中のモジュール指定、タイプ指定をはずすことができます。Cソース出力(「/fast」「/compact」)は、一般に実行性能は高いのですが、コンパイルできるファイルのサイズがCコンパイラに依存するので、モジュール分割が必要となります。またこの時、モジュール間の呼び出し関係に応じ public宣言とextern宣言が必要となります。,コンパイラに渡すファイル名(「*.pl」や 「*.obj」等)についてはいくつでも指示が可能ですが、数が多い場合にはコマンドラインに入力できる文字数を超えてしまうことがあります。この時には「/f」によるファイル指示を行ないます。,ワークエリア指定のない場合はデフォルトの値が使われます。スタック等のサイズは、インタプリタ上で組込述語「statistics/0」を使って必要な大きさを割り出します。,「top_level/0」述語と「/i」指示について。,「 top_level/0 」を定義し、実行プログラムを生成するとき「/i」を指示していないと、必要な組込述語のみをリンクするだけですので実行ファイルが小さくできます。,拡張Prologインタプリタのトップレベルや、入力値を述語として呼び出す「read(A),call(A)」のように、いかなる組込述語が実行されるかわからないような場合には「/i」を指示しておくべきです。,トップレベル述語(top_level/0)の定義がなく、「/i」オプションも指定しないと、ファイル中で定義されpublic宣言された組込述語と「halt/0」以外の組込述語は組込まれません。,単独実行プログラムの場合で「d_cursor/2」等のカーソル、スクロール制御を行う場合には、「/curses」オプションを指定してください。,ストップキー(CTRL-C)・ブレークキーによる割り込みで実行を中断したときの選択肢は、スタンドアロンプログラムの場合「abort」「continue」と「exit」のみとなります。,「exit」は処理を中断しOSへ戻ります(「/i」指定の場合「exit」の選択肢はありません)。,「abort」はエラー255を実行するので、「errorset」で捕捉可能なためユーザーによる制御が可能です。,「errorset」で捕捉されない場合は「halt」します。,「continue」は割り込みを取り消します。,【使用例】,①,C:¥>azpc -p my_append.pl /e prolog /i,「my_append.pl」を組込んだ拡張Prologインタプリタを生成します。,②,C:¥>azpc -p lisp.pl /e azlisp,単独実行プログラム「azlisp」を生成します。,③,C:¥>azpc -p queen.pl /byte,インタプリタにロード可能なバイトコードファイル「queen.b」が生成されます。,一度コンパイルしたPrologソースは、「xxx.c」及び「xxx.obj」または、「xxx.b」が生成されていますから、次回からはこれを指定することによってコンパイル時間の短縮がはかれます。,提供インタプリタには標準ライブラリに含まれる組込述語以外にPrologで記述しコンパイルされたコンパイル組込述語が100述語ほど含まれています。,コンパイラで実行ファイルを生成する際、ユーザーソースにはこれらの述語が自動で組み込まれます。(mlt_child.pl, odbc_prolog.plを除く),自分で定義した同名の述語があるなど組み込みたくない場合はコンパイル時にオプション /no_exlib を指定してください。,コンパイル組込述語のソースはインストールディレクトリ(本マニュアル”2.インストールと環境設定”参照)の system/pl 下にあります。,なお、呼び出し元ソースにはそのコンパイル組込述語のextern宣言(本マニュアル”7.4.(4) extern宣言"参照)をつけておくと呼び出しが高速になります。,【コンパイル組込述語一覧】,<fs_utility.pl 15述語>,fs_av/3 fs_body/2 fs_new/3 fs_list/2 fs_member/2 fs_copy/2 fs_append/3,fs_appends/2 pnames/2 pvalue/3 fs_replace/4 fs_rm/3 fs_writeAVM/1,tfs_assert/1 tfs_conv_pred/2,<iso_pred.pl 19述語>,abolish/1 once/1 atom_concat/3 atom_codes/2 atom_chars/2 number_chars/2,char_code/2 get_char/1 get_char/2 open/3 current_predicate/1,current_prolog_flag/2 set_prolog_flag/2 copy_term/2 sub_atom/5 uppercase_atom/2,lowercase_atom/2 downcase_atom/2 number_codes/2,<macro_consult.pl 1述語>,macro_consult/1,<mlt_child.pl 0述語>,子タスク用TopLevel,<mlt_parent.pl 13述語>,mlt_proc/2 mlt_proc/5 mlt_proc2/2 mlt_kill/1 mlt_terminate/1 mlt_send/2,mlt_send_cmd/2 mlt_receive/2 mlt_receive/3 mlt_scan/3 mlt_scan2/3,mlt_scan_each/2 mlt_reflesh/2,<odbc_prolog.pl 13述語>,odbc_open/3 odbc_close/0 select_each/3 select_each/4 select_each/6 fetch_one/4,is_null/1 sql_cancels/1 exec_direct/2 exec_directs/3 exec_directs_pre/4,exec_directs_post/2 exec_directs_main/4,<setof.pl 12述語>,setof/4 setof/3 bagof/3 ^ / 2 s_qsort/3 findall/3 f_bagof/3 f_findall/3,f_setof/4 f_setof/3 f_assert/1 f_assertz/1,<utility.pl 21述語>,read_line/4 atom_appends/2 p_puts/2 get_chars_list/4 write_list/1,write_listnl/1 my_system_name/1 rexpl/3 rexpl/4 rexpl/5 rexpl/6,pattern_compile/2 rexpl_search/6 printf/1 printf/2 sprintfl/3 sprintf/3,spf_format/3 call_count_check/1 call_count_set/1,local_time/1(Windows用ソース),<system/C/mytime.c>,local_time/1(Linux用ソース)"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_7","title":"7-7.コンパイルコードとインタプリタコードの動作の違い","text":"7-7.コンパイルコードとインタプリタコードの動作の違い,コンパイルコード(コンパイルして出来た単独実行プログラム)は、インタプリタ上で動作した場合と異なる動きをすることがあります。,Prologソースコードを書く上での注意点,インタプリタ上では、異なる複数のファイルをコンサルトした場合、各ファイルに定義された述語を相互に呼び出すことができますが、コンパイルコードを実行する場合には、モジュール(Cソースでは1ファイルになる)間で相互に明示的なpublic宣言、extern宣言がなされていなければなりません 。,実行中にプログラム自身を操作(追加・削除・組立て・取り出し)する述語では特に動作の違いに注意が必要です。,以下、2について具体的に説明します。,i) 追加、削除、取り出し(assert・retract・abolish),次のようなプログラムの場合、述語「a/0」が呼ばれると、インタプリタでは「b/0」の3つ目の節がヒープに「assert」されますが、コンパイルコードの場合は「assert」されません。,b:-write(1).,b:-write(2).,a:-b,assert((b:-write(3))),fail.,仮にこのプログラムに,:-public b/0.,を追加すると、上記「assert」の場所で“組込述語と同じユーザ述語の「assert」をしようとしている”というエラーになります。,同様に「retract」「abolish」述語で削除しようとした述語が「static」述語であれば失敗し、public宣言されていればエラーとなります。,ii) 組立て(=..),次のようなプログラムの場合、「=..」(ユニブ)で作った項をコールしようしても失敗します。,a:-A=..[b,X],call(A).,b(1).,この場合は,:-public b/1.,の宣言が必要です。"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_8","title":"7-8.インタプリタからのバイトコードコンパイラ起動","text":"7-8.インタプリタからのバイトコードコンパイラ起動,下記のようにすると、インタプリタの中からAZ-Prologコンパイラを/byteモードで起動し、コンパイル結果のバイトコードを取り込むことができます。,| ?-compile(ファイル名).↓,Prologのソースファイルをインタプリティブバイトコードに変換し、インタプリタ上にロードします。コンパイラ(azpc)で直接バイトコードコンパイルした場合はバイトコードファイル(拡張子「.b」)が作成されますが、この場合は作成されません。,コンパイラの起動には,インタプリタからコンパイラを子タスク(プロセス)として立ち上げるための十分なメモリがあること。,コンパイラ(AZPC.EXEまたはazpc)が格納されているディレクトリへのパスが設定されていること。,の2点が必要です。,メモリ不足で立ち上げができない時には、一度OSへ戻って直接AZPCを起動し、バイトコードファイル生成後インタプリタにロードさせなければなりません。,C:¥>azpc -p ファイル名 /byte↓,これ以外に、インタプリタの中からバイトコードコンパイラを起動する方法を次に示します。,| ?-compile_all.↓,ヒープ領域内の全述語を一度中間ファイルへ出力し、ここに含まれる全述語をpublicとしてコンパイルし、インタプリタにロードします。コンパイル結果はメモリ上に展開されますが、この場合もバイトコードファイルは残りません。,既にコンパイルされているバイトコードをロードするには以下のようにします。,| ?-b_load(ファイル名).↓| ?-b_load(ファイル名並びリスト).↓,ファイルは必ず拡張子「.b」を持つバイトコードファイルでなければなりません。その前提で、拡張子は省略可能です。,<例>,| ?-b_load([azedit,setof]).↓| ?-b_load(azedit).↓,バイトコードのロードはモジュール(ファイル)単位に行われます。同一名のモジュールが再ロードされたときは、以前に同一モジュール内で定義されていた述語は全てヒープ領域から消去されます。,また、複数モジュールで同じ述語(同一名/アリティ)が定義されている場合、後でロードされたモジュールの述語定義が優先されます。但し、あるpublicな述語(仮にp1)がモジュール内で定義され、かつp1がモジュール内の他の述語(仮にp2)から呼び出されている場合、後で同一述語p1が新しく定義された別モジュールがロードされても、述語p2が呼び出すp1は同じモジュール内の元の定義のままです。コンパイル時にモジュール単位で呼び出し関係が決定してしまっているからです。,<例>,file1.b : reverse/2の定義,↓,my_append/3 の定義,file2.b : my_append/3 の別定義,| ?-b_load(file1).↓,| ?-b_load(file2).↓,file1でロードされた「my_append/3」が消去され、file2の「my_append/3」がpiblicになる。,但し「reverse/2」の内部で呼び出される「my_append/3 」は、file1に含まれていたもののままである。,(file1の「my_append/3」は、「reverse/2」に対応する関数内にコードは残っているが、直接呼び出すためのエントリポイントがなくなるため。),これらの他に、AzEditの中からエディタ上のプログラムをバイトコードコンパイル・ロード出来ます。,詳しくは本マニュアルの「9-11.内蔵エディタ(AzEdit)」を参照してください。"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_9","title":"7-9.コンパイル時のエラー","text":"7-9.コンパイル時のエラー,コンパイル実行時にエラーが発生すると、その内容を表示して停止します。 (実際のメッセージは英語です。),1,コマンドラインエラー(Command Line Error),コマンドラインの記述に誤りがある。,2,スタック(ヒープ)オーバーフロー,ワークエリアのどれかが不足した→コマンドラインの指定で増やす。,3,シンタクスエラー,ソースファイルにシンタクスエラーがある。このときファイル名、エラー表示節番号(ファイル中の節定義の順位)とその節を表示します。,4,Cコンパイラ・リンカエラー,Cコンパイラ・リンカのマニュアルを参照してください。"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_10","title":"7-10.リソースファイル(Windowsのみ)","text":"7-10.リソースファイル(Windowsのみ),objディレクトリの中にリソースファイル「prolog.res」が入っています。,これはアイコンのみを含むリソースファイルですが、アプリケーションのコンパイル時に,C:¥>azpc -p ..... /lib ¥prolog.res,のように指定すれば、作成される実行ファイルのアイコンが「prolog.exe」のアイコンとおなじものになります。"}); htmllist.push({"file":"manuals/manual_compiler.html#compiler_11","title":"7-11.総括入力ファイルによるAZ-Prolog 各種インタプリタの生成","text":"7-11.総括入力ファイルによるAZ-Prolog 各種インタプリタの生成,総括入力ファイルとは、AZ-Prologが提供する各種インタプリタを生成するために、コンパイラazpcのコマンドラインに付加すべき情報(ソースファイル、ライブラリ、その他の指示オプション等)がすべて記述されたファイルです。/fオプションに先行する#defineで宣言された文字列により、情報が取捨選択されるように記述されています。,総括入力ファイル「prolog_exe.txt」は、パッケージの「system/make」に格納されています。,「%」以降は改行までコメントと見做します。,提供される各種インタプリタは、以下の様なコンパイラオプション指定で生成されています。,C:¥>azpc -p #define cgi /f prolog_exe.txt,C:¥>azpc -p #define win /f prolog_exe.txt,C:¥>azpc -p /f prolog_exe.txt"}); htmllist.push({"file":"manuals/manual_interface.html#c_lang","title":"8-1.概要","text":"8-1.概要,AZ-Prologは、ユーザが記述したC言語のプログラムをPrologとリンクする機能を提供しています。,それは言換えれば、AZ-Prologの組込述語をC言語で記述して追加することを可能にする機能です。,AZ-PrologコンパイラはPrologで記述されたプログラムをC言語ソースに変換し、そのC言語ソースを各OSのCコンパイラ・リンカを起動して実行モジュールを生成します。,したがって、AZ-PrologコンパイラがPrologを変換して出力したC言語ソースであろうと、ユーザが記述したC言語ソースであろうと、枠組が同じならば同じ扱いができます。,C言語プログラムのコンパイル・リンクも、AZ-Prologコンパイラの引数にファイル名を指定して行います。,<例>,C:¥>azpc -p cprogram.c /i /e myprolog,コマンドラインには複数のCソース、Prologソースを記述できます。,C:¥>azpc -p cpro1.c ppro.pl cpro2.c /i,この例では、C言語ソースファイルcpro1.c、cpro2.cとPrologソースファイルppro.plを一緒にコンパイル・リンクして、拡張インタプリタ(実行プログラム名は省略時のデフォルトprolog)を生成しています。"}); htmllist.push({"file":"manuals/manual_interface.html#c_lang_2","title":"8-2.C言語ソースプログラムの記述方法","text":"8-2.C言語ソースプログラムの記述方法,この節では、PrologとリンクするためのC言語ソースの書き方を説明します。,そのC言語ソースは基本的にAZ-Prologコンパイラから中間で出力されるC言語ソースと同じ枠組みを持たせる必要があります。,リンク可能なC言語ソースプログラムは次の枠組みを持ちます。,★ヘッダファイルのインクルード,★モジュールファイル初期化関数の定義,★各関数の定義,以下、順に説明します。,8-2-1.ヘッダーファイルのインクルード,第一の枠組として「azprolog.h」というヘッダファイルのインクルードがあります。,ユーザが定義するヘッダファイル以外に、次の1行を必ず追加してください。,#include <azprolog.h>,このヘッダファイルには、Prologとリンクするための情報が書かれています。,8-2-2.モジュールファイル初期化関数の定義,まず、次のC言語ソースプログラムの例を見てください。,ファイル名“cpro.c”,#include <azprolog.h>,pred P2_cprogram(Env) 組込述語 cprogram/2 となる関数の定義,Frame *Env;,{,:,処理コード(述語の処理を関数内に記述),:,},: 同様に他の述語を関数で定義,int initiate_cpro(Frame *Env) /* 初期化関数 */,{,put_bltn("cprogram",2,P2_cprogram);,: 定義された各述語について、put_bltn(..)を同様に記述。,:,その他の初期化コード,:,return 1;,},この中でinitiate_cpro(Frame *Env) という関数が、モジュールファイル初期化関数と呼ばれるものです。これはリンクするモジュール(Cソースファイル)に含まれる組込述語を、システムに登録するための関数です。,モジュールファイル初期化関数の関数名は「initiate_ファイル名」としてください。つまり、個々のCソースファイル毎に初期化関数は必要になる訳です。この関数内には、そのファイルで定義されたCリンク組込述語の登録情報の記述及び、必要な初期化コードを入れておきます。,個々のCリンク組込述語登録の記述:put_bltn(“組込述語名”,アリティ,関数名);,組込述語名と関数名は、必ず次の対応をとるようにします。 {}部分は実際の数字/名前に置き換えます。,関数名:P{アリティ}_{組込述語名},冒頭の例ではCリンク組込述語「 cprogram/2 」を追加するので,P2_cprogram(),となっています。,この枠組は、他のモジュール、特にコンパイルコードで、該当する関数を決定するためのものですから、必ず守るようにしてください。また、この関数が実行される前に該当の関数を定義しておきます。,azpcで実行プログラムを生成すると、リンク用のファイル「userfile.c」が作られます。,このファイルの内容は次の様なものです。,ファイル名 “userfile.c”,void user_file(),{,initiate_{ファイル名1}(NULLFRAME);,initiate_{ファイル名2}(NULLFRAME);,:,},関数「user_file()」の本体には、リンクした全てのユーザ定義ファイルの初期化関数の呼び出しが列挙されています。プログラムを実行すると、ワークエリアの初期化等の後でこの関数が呼ばれます。この時、各ファイルの初期化関数が順に呼び出されて、実行プログラムに述語の組込登録をする仕組になっています。,8-2-3.各関数の定義,組込述語を定義する関数の名前は前述の関数名のルールに従います。,関数は「Frame *」型の引数を一つだけとり、「pred」型の値を返します。,「Frame」「pred」 はいずれも「azprolog.h」で定義されたtypedef名です。,以下では次の二つの場合に分けて関数の記述方法を説明します。,(A)単純な決定性組込述語をC言語で直接記述する場合,(B)コンパイラが出力したCプログラムをテンプレートとして利用する場合,なお、以下で使用されるシステム定義の関数の詳細は、次節の関数リファレンスを参照してください。,(A)単純な決定性組込述語をC言語で直接記述する,実際にC言語インターフェースで記述する述語のほとんどはこのタイプに属するものとなります。,簡単なプログラム(内容自体はあまり意味が無い)を例に説明します。,次のような計算を実行する述語を作ります。,num_crunch(X,Y):-Y is 1/(1+exp(-X)).,同じことをAZ-PrologのC言語インターフェースを使って記述すると、次のようになります。,システム関数(GetDouble等)でエラーが発生する可能性がありますが、事前の引数の型チェックやエラー処理はここでは簡単のため省略しています。,pred P2_num_crunch(Env) ・・・・・・・・・・・・・・・・①,Frame *Env;,{,double x,y;,x=GetDouble(next_var_cell-2); ・・・・・・・・・・②,y=1.0/(1.0+exp(-x));,if(UnifyDouble(Env,next_var_cell-1,y)) ・・・・・・③,YIELD(DET_SUCC); ・・・・・・・・・・・・・④,else,YIELD(FAIL);,},①~④が Prolog とのインターフェース部分です。以下の表で説明します。,①,関数の型、名前、引数はこのようになります。,ENVにはProlog特有の実行制御のための情報が入っていますが、ここで説明しているようなタイプの述語(決定性述語)では直接には使用しません。(一部システム関数・マクロの引数として使用する場合があります),②,渡された引数の値を取得します。,Prolog側での呼出しがpred(arg1,arg2,・・・・,argn). となっている時、argiの内容はnext_var_cell - n + i - 1 の位置に置かれています。,next_var_cell - n   → arg1next_var_cell - n + 1 → arg2::next_var_cell - 1 → argn,next_var_cell (スタックポインタ)は「TERM *」型の外部変数です。,ただし、上の対応は関数呼出し直後のもので、システム関数・マクロを使用するとnext_var_cell が変化することがあるので、固定ではありません(関数リファレンス参照)。また引数領域から現在の next_var_cellの値の直前までは、その述語用の作業領域として使用してよいようになっています。,システム関数・マクロを介さず直接 next_var_cellの値を増加させることは禁止されています。 next_var_cellの値を変化させるシステム関数・マクロを多用する場合は初期の値をローカル変数にセーブしておくと引数へのアクセスに便利でしょう。,③,計算結果(y)を引数(Y)とユニファイします。,値をProlog側に返す場合はユニファイを行います。ユニファイは失敗する可能性があることに注意してください。ユニファイを行うシステム関数(上記の例ではUnifyDouble())。8-2-4.関数リファレンス d)引数へのユニファイ参照)は成功すると1、失敗すると0を返します。,④,成功または失敗でPrologに戻ります。,YIELDはreturn文に展開されるマクロです。YIELD(DET_SUCC)は決定性の成功(バックトラックしてもここには他の選択肢が無い)、YIELD(FAIL)は失敗を意味します。いずれの場合も使用した作業領域はProlog側で解放するようになっています。,注),DET_SUCC、FAILは、それぞれ1、0を pred型にCASTしたものです。,YIELD(UnifyDouble(Env, next_var_cell - 1, y));,とすることができます。,(B)テンプレート出力の利用,C言語による操作を行いたい部分にスタブ宣言をした述語を含めてProlog述語を作ります。,:-extern c:stub/3.,f00(X):- ・・・・・・, stub(X,A,B), ・・・.,このファイルをAZ-PrologコンパイラでコンパイルしてC言語ファイルを出力させます(/nccオプションを指定)。出力プログラムはおおよそ次のようになります。,extern pred P1_foo();extern int stub();::pred P1_foo(Env)register Frame *Env;{ Frame Now; Now.Link = Env; LINK(Env, -, -); : : if( !stub(&Now,Env->Local-1,Env->Global,Env->Global+1) ) YIELD(FAIL); : :},関数stubはint型のpublicな関数として宣言され、これを呼び出す1行(if文)が関数P1_fooの中に追加されていますが、関数の雛型は生成されません。Prologソースの中でのstub述語(テンプレートを出力するためのあくまで仮の述語)の呼び出し形式(上記の例では、変数Xの値を入力として受取り、変数AとBが出力として返す)が、生成されたstub関数呼び出し形式に反映されます。,ここで関数stubの内容を作成し(あるいは関数 stub の呼出しを直接置き換えて)再びコンパイル(今回はリンクまで。リンクバッチmkazを使用)します。この例では、スタブ関数の呼出しは第1引数に環境フレーム、第2引数以降にもとのProlog呼出しでの引数の並びに対応するTERM *型のデータが渡されています。,引数に「Frame* Env」を取るシステム関数(8-2-4.関数リファレンス参照)には、この第1引数の値を渡します。スタブ関数の戻り値は整数で1が返された時は成功、0の時は失敗として扱われます。,8-2-4.関数リファレンス,a)登録関数,以下の2関数は初期化関数(initiate_XXX)からのみ使用することができます。,void put_bltn(char *predicate_name, int arity, pred (*function)()),名前 predicate_name,アリティ arity の組込述語を登録し、処理関数を「function」とします。,BASEINT PutSystemAtom(Frame *Env, char *name),名前 name をもつアトムをシステムアトム(GCによって回収されない)として登録し、アトム番号を返します。アトム番号とは全てのアトムに対して割り当てられ、個々のアトムを一意に特定する整数値です。,b)型チェック,int IsAtom(Term *t),tがアトムの時1を、それ以外の時0を返します。,int IsInt(Term *t),tが整数の時1を、それ以外の時0を返します。,int IsDouble(Term *t),tが浮動小数点数の時1を、それ以外の時0を返します。,int IsCompTerm(Term *t),tが複合項の時1を、それ以外の時0を返します。,int IsNil(Term *t),tがアトム[ ](空リスト)の時は1を、それ以外の時は0を返します。,int IsCons(Term *t),tが[A|B]の形の複合項の時1を、それ以外の時0を返します。,int IsUndef(Term *t),tが未定義変数の時1を、それ以外の時0を返します。,c)引数の取得,以下の関数はいずれもエラーを発生することがあります。プログラムの実行を中断させないためには、予めb)の型チェック関数で引数のチェック等をした上で使用するようにしてください。,BASEINT GetAtom(Term *t),tがアトムの時アトム番号を返します。それ以外の時エラー(Illegal argument)となります。,BASEINT GetInt(Term *t),tが整数の時その値を返します。それ以外の時エラー(Illegal argument)となります。結果は int 型または long 型に代入できます。,double GetDouble(Term *t),tが浮動小数点数の時その値を返します。,それ以外の時エラー(Illegal argument)となります。,int GetFunctor(Term *t, BASEINT *f),複合項tのファンクタを取得する関数です。,tが複合項の時、引数fの指す領域にtのファンクタのアトム番号を入れます。tが複合項でない時はエラー(Illegal argument)となります。,void GetArg(Term *t, int n),複合項tのn番目の引数を取得する関数です。,tが複合項の時、next_var_cell の値を+1して新たに領域を確保した上で、next_var_cell -1の位置にtのn番目の引数を入れます。tが複合項でない時、n がアリティより大きい時はエラー(Illegal argument)となります。,void GetCons(Term *t),tが [A|B] の形の項の時、next_var_cell の値を+2して新たに領域を確保した上で、next_var_cell -2の位置にAを,next_var_cell -1 の位置に B を入れます。tが[A|B]の形の項以外の時はエラー(Illegal argument)となります。,d)引数へのユニファイ,以下の関数はいずれも、ユニファイに成功すれば1を、失敗すれば0を返します。第1引数には述語定義の唯一の引数Envをそのまま渡します。,int UnifyE(Frame *Env, TERM *t1, TERM *t2),t1とt2をユニファイします。,int UnifyAtomE(Frame *Env, TERM *t, BASEINT n),tとアトム番号nをもつアトムをユニファイします。,int UnifyIntE(Frame *Env, TERM *t, BASEINT i),tと整数iをユニファイします。BASEINT はlong型です。,int UnifyDouble(Frame *Env, TERM *t, double f),tと浮動小数点数fをユニファイします。,エラー(Global stack Overflow)を起こす場合があります。,int UnifyCompTerm(Frame* Env, TERM* t, BASEINT func, int ari,TERM* arg1, ...),tと複合項(func以降で与える)をユニファイします。複合項は、ファンクタがアトム番号funcのアトム、アリティがariで、引数は arg1,以降にari個並べ、何れもTerm * 型です。,エラー(Global stack Overflow)を起こす場合があります。,int UnifyCons(Frame *Env, TERM *t, TERM *A, TERM *B),tと項 [A|B] をユニファイします。,エラー(Global stack Overflow)を起こす場合があります,e)その他,void MakeUndef(Frame *Env),next_var_cellを+1して領域を確保し,next_var_cell –1 の内容を未代入変数とします。,複合項を合成する時の中間結果に使用できます。引数nの複合項の領域を確保するには、本関数をn+2回呼び出します。,エラー(Global stack Overflow)を起こす場合があります。,int Bn_xxx(Frame *Env, Term *t1, ・・・),決定性組込述語xxx/nを呼び出します。t1以降にはn個のTerm *型の引数を与えます。成功したら1を、失敗したら0を返します。,但し、記号組込述語(述語名が記号)については、呼び出す関数名はxxxに記号を当てはめた形式ではなく、内部関数名です(この後に続く「付表:記号組込述語の内部関数名」を参照)。,void Atom2Asciz(BASEINT atom, char *buffer),アトム番号atomの名前をbufferにコピーします。 bufferは必要な文字配列の領域を予め確保します。az_get_atom_length()で必要な長さを調べることもできます。,BASEINT Asciz2Atom(Frame *Env, char *name),名前がnameであるアトム(無ければ新たに登録)のアトム番号を返します。,エラー(Heap Overflow)を起こす場合があります。,GCが起こると使われていないアトムは登録を抹消されるので、同じ名前でこの関数を呼んでも常に同じ値を返すとは限りません。この関数の戻り値の有効期間は制御が他の述語関数に移る(ような呼び出し、または成功/失敗でのリターン)か、次にこの関数がコールされるまでに限定されます。従って無効になる前に UnifyAtom等のアトム番号を引数にとる関数で使用する必要があります。,初期化関数中でPutAtomによって返されたアトム番号については、このような制限はありません。,int az_get_atom_length(BASEINT n);,引数nで指定したアトム番号のアトムの名前のバイト数を返します。,int az_charsetmode(void);,現在の文字エンコードを取得します。戻り値は以下のいずれかです。,0:sjis, 1:euc, 2:utf8,次の定数が定義されていますのでご利用ください。,#define AZ_ENC_SJIS (0),#define AZ_ENC_EUCJP (1),#define AZ_ENC_UTF8 (2),int az_enc_len(int encode, const unsigned char* p);,文字列の先頭文字のバイト長を取得します。,また、次の定数も定義されていますのでご利用ください。,#define AZ_MAX_ATOM_LENGTH  アトム名の最大バイト長,付表:記号組込述語の内部関数名,述語のアリティは全て2。内部関数はFrame *Envと2つのTERM *型の引数を取ります。,記号述語,内部関数,=,B_equal(),=:=,B_eqnum(),=/=,B_noteqnum(),<,B_ltnum(),>,B_gtnum(),=<,B_lenum(),>=,B_genum(),=..,B_univ(),==,B_eqterm(),/==,B_noteqterm(),¥==,B_noteqterm(),@<,B_ltterm(),@=,B_leterm(),@>,B_gtterm(),@>=,B_geterm()"}); htmllist.push({"file":"manuals/manual_interface.html#c_lang_3","title":"8-3.他システムの一部としてAZ-Prologの組込み","text":"8-3.他システムの一部としてAZ-Prologの組込み,8-2では、AZ-Prologの述語をC言語で記述する方法を説明しましたが、main関数をもつ C++などで書かれた他システムの一部としてAZ-Prologを利用することもできます。それにはインターフェース関数(8-3-1参照)を使用します。,8-3-2では、単純なprologのゴールをC++プログラムからAZ-Prologを利用して実行する例を示していますが、prologで書いた述語をコンパイラazpcで変換したCソースや、C言語で記述したユーザ定義述語もリンクさせることが可能です。この場合、初期化関数および初期化が必要ですので、azpc が生成するuserfile.c もコンパイルリンクします。但し、prologのモジュールには top_level/0 の定義はしないでください。 main関数に変換されるからです。,8-3-1.インターフェース関数,他言語からAZ-Prologを利用するインターフェース関数を解説します。何れの関数も、正常終了の時は1を、エラー終了の時は0を返します。,(1) AZ-Prologの初期化,AZ-Prologの利用のため、領域を確保して初期化します。領域指定する引数は-h/-l/-g/-aの各サイズです。直接指定しない場合のワークエリアサイズの決定ルールは、Prologインタプリタ等のPrologアプリケーションの場合と同じです(3-3-7参照)。,int az_init(int argc, char* argv[]),int argc:,AZProlog 初期化パラメータの引数の総個数(プログラム名も含む),char *argv[ ]:  ,AZProlog 初期化パラータの文字列を指すポインタの配列,(2) AZ-Prologの終了,AZ-Prologの使用を停止し、領域を開放します。,int az_end(void),(3) Prologゴール実行 (結果取得が不要な場合),Prologゴールを実行します。実行後のバックトラックはできません。,int az_exec(char *goal),char *goal: Prologのゴールを文字列で与えます。,(4) Prologゴール実行,結果取得,Prologゴールを実行し、ゴールに含まれる変数の値を文字列で取得します。,結果取得後のバックトラックはできません。,int az_exec_unify(char *goal,int n, ... ),char *goal:  ,Prologのゴールを文字列で与えます。,int n :,トップレベルのゴールに含まれる、値を取得する変数の(先頭から数えた)数を与えます。,... :  ,変数の値を文字列として格納するため、n個分の文字型配列を並べます。,同一の変数が複数ある場合は、その変数が最初に出現した位置に格納されます。, ,< 例 >,char retA[256],retB[256],retC[256];,az_exec_unify("my_goal(1,A,B,A,C)",3,retA,retB,retC);,8-3-2.C++からの利用例,C++でどのようにインターフェース関数を用いてAZ-Prologを利用するのか、記述方法の簡単な例と、コンパイル・リンク、そして実行までを見てみます。,C++プログラム例,C++プログラムからprologのゴール append([1,2,3],[4,5],L)をAZ-Prologを利用して実行し、結果を取得して表示する例です。,/* callaz.cpp */,#include <stdlib.h>,#include <stdio.h>,#include <stdarg.h>,extern "C" { extern int az_init(int argc,char **argv); },extern "C" { extern int az_end(void); },extern "C" { extern int az_exec_unify(char *args, int n,... ); },int main(int argc, char **argv){,int argcp = 3;,char *argvp[]= {(char *)"my_prolog",(char *)"-h",(char *)"100"};,char goal[] = "append([1,2,3],[4,5],L)";,char retVar[256];,if(az_init(argcp,argvp)){,printf("AZ-Init OK¥n");,} else {,printf("AZ-Init error!¥n"); exit(1);,},if(az_exec_unify((char *)goal,1,retVar)){,printf("ret = %s¥n",retVar);,} else {,printf("exec Fail!¥n");,},if(az_end()) {,printf("AZ-End OK¥n");,} else {,printf("AZ-End error!¥n");,},},コンパイル・リンク,[Windows版],c:¥test>cl callaz.cpp /link "<INST_DIR>¥lib¥azp.lib",はAZ-Prologをインストールした場所です。Windows 64bit版をデフォルトでインストールした場合は、C:¥Program Files¥AZ-Prolog.9.24となります。,注意:Microsoft Visual Studio 2010では、リンク時以下のエラーが発生します。,「error LNK2019: 未解決の外部シンボル __report_rangecheckfailure が関数 _Read_GetTokenで参照されました。」,Visual Studio 2010には対応していませんので、Visual Studio 2012以降のバージョンでコンパイル・リンクして下さい。,[Linux版またはMac版],$ g++ -Wall -o callaz callaz.cpp -lazp -lm -ldl,実行と結果表示,$ ./callaz,AZ-Init OK,ret = [1,2,3,4,5],AZ-End OK"}); htmllist.push({"file":"manuals/manual_function_summary.html","title":"9-1-1.AZ-Prolog付属の拡張機能ライブラリ","text":"9-1.概要,9-1-1.AZ-Prolog付属の拡張機能ライブラリ,本パッケージには、機能別にコンパイルされ必要に応じてロードできる拡張機能のダイナミックリンクライブラリが付属しています。一例としてエディタAzEditで言えば、Windows版なら「azedit.dll」、Linux版なら「azedit.so」がそれです。以下ではこれらを総称し「dll/so/dylib」と表記しています。これらは、AZ-Prologのインストールディレクトリ下の「system」ディレクトリ(注1)にソースで提供されていますので、機能の詳細を確認することができ、必要に応じ修正しコンパイルしなおすことができます。,注1.拡張機能ライブラリのソースファイル格納ディレクトリ,Windows版,%AZProlog%¥system¥ext, %AZProlog%¥system¥pl,Linux版,${AZProlog}/share/azprolog/system/ext, ${AZProlog}/share/azprolog/system/pl,Mac版,${AZProlog}/share/azprolog/system/ext, ${AZProlog}/share/azprolog/system/pl,*AZPrologはインストール時に設定される環境変数です。,各ディレクトリにはコンパイルのためのmakefileも含まれています。,また、個々の拡張機能を応用したサンプルプログラムがAZ-Prologのインストールディレクトリ下の「sample」ディレクトリ(注2)にソースで提供されていますのでご参照ください。,注2.拡張機能応用サンプルプログラム格納ディレクトリ,Windows版,%AZProlog%¥sample,Linux版,${AZProlog}/share/azprolog/sample,Mac版,${AZProlog}/share/azprolog/sample,本パッケージで提供される標準インタプリタをMakeするmakefileはインストールディレクトリ下の「system/make」ディレクトリにありますので、ユーザプログラムをコンパイルし、スタンドアローン実行プログラムを作成する場合の参考にしてください。"}); htmllist.push({"file":"manuals/manual_function_summary.html#func_2","title":"9-1-2.「dll/so/dylib」化されている拡張機能を利用するには","text":"9-1-2.「dll/so/dylib」化されている拡張機能を利用するには,「dll/so/dylib」化されている拡張機能を利用するには、利用開始前に次の述語を呼び出してください。,:- dlib_require(拡張子を除いた「dll/so/dylib」名).,提供される各「dll/so/dylib」はインストールディレクトリ下(注3)に格納されており、パスを省略した時はここを参照します。,注3.拡張機能「dll/so/dylib」格納ディレクトリ,Windows版,%AZProlog%¥lib¥ext,Linux版,${AZProlog}/lib/azprolog/ext/,Mac版,${AZProlog}/lib/azprolog/ext/,<例>- dlib_require(mecab).,  この述語が失敗した場合は、次の述語でステータスを取得できます。,  :- dlib_get_error_str(S),name(A,S).,ユーザー作成の「dll/so/dylib」も同様に呼び込むことができます。,但し、「/static」オプションを付けてコンパイルした拡張インタプリタ(ユーザプログラムをスタティックリンク)からは、組込述語 dlib_require/1 で他の「dll/so/dylib」を呼ぶことはできなくなるので注意してください。この場合、必要な拡張機能があれば、それらも合わせてスタティックリンクする必要があります。その方法については「9-1-5.拡張機能のスタティックリンク方法」を参照してください。"}); htmllist.push({"file":"manuals/manual_function_summary.html#func_3","title":"9-1-3.拡張機能のOS別実装一覧表","text":"9-1-3.拡張機能のOS別実装一覧表,Win ,Linux/Mac,dll/so/dylib,機能拡張,リンク方法,備考,○,○,×,9-2..素性構造型,基本インタプリタにリンク済(スタティック), ,○,○,○,9-3.制約論理,:- dlib_require(clp).,提供ソースファイル:clp.pl(*1),○,○,×,9-4.並列処理支援機構,子プロセス用インタプリタ(prolog_c)にリンク済(スタティック),提供ソースファイル:mlt_child.pl、mlt_parent.pl(*2),○,○,×,9-5.CGIインターフェースとユーティリティ,CGIインタプリタ(prologcgi) にリンク済(スタティック),提供ソースファイル:prologcgi.pl(*2),○,○,○,9-6.鬼車,:- dlib_require(oniguruma).,提供ソースファイル:oniguruma.c(*1),事前準備: 正規表現ライブラリ”鬼車"はパッケージに同梱。最新版に差し替える場合のみダウンロード・インストール,○,○,○,9-7.Mecab/Cabocha,:- dlib_require(mecab).,提供ソースファイル:mecab.c、aze_cenc.c、aze_api.c(*1),事前準備:形態素解析エンジン”MeCab”ダウンロード・インストール,○,○,○,9-8.ソケット,:- dlib_require(socket).,:- dlib_require(socket_ssl).,:- dlib_require(websock).,提供ソースファイル:socket.c、socket_ssl.c、websock.c client.c util.c(*1),事前準備: [socket_ssl]OpenSSL、Cryptoダウンロード・インストール,限定機能:Unix(ドメイン)ソケット(socketライブラリ)、WebSocketはLinux版のみ,○,○,○,9-9.Redisインターフェース,:- dlib_require(redis).,提供ソースファイル:redis.c、putil.c、putil.h(*1),事前準備:Key-ValueストアRedisサーバ/hiredis(Cクライアント)ダウンロード・インストール,○,×,○,9-10.ODBC,:- dlib_require(odbc).,提供ソースファイル:odbc_prolog.pl、odbc.c(*1),事前準備: RDBMS(MS-ACCESS、SQL Server等)/ODBCドライバダウンロード・インストール、データソース設定、ODBC接続テスト,○,×,×,9-11.OLEオートメーション,基本インタプリタにリンク済(スタティック), ,○,○,○,9-12.エディタ(AzEdit)    ,:- dlib_require(azedit).,提供ソースファイル:azedit.pl(*1),○,○,×,9-13.その他,各インタプリタにリンク済(スタティック),提供ソースファイル:iso_pred.pl,utility.pl,setof.plなど(*2),*1:ダイナミックリンクする拡張機能のソースファイルはsystem/ext以下の機能別サブディレクトリあります。,*2:スタティックリンクされている拡張機能のソースファイルはsystem/plの直下にあります。"}); htmllist.push({"file":"manuals/manual_function_summary.html#func_4","title":"9-1-4.dll/so/dylibの基本的な作り方","text":"9-1-4.dll/so/dylibの基本的な作り方,ダイナミックリンクライブラリ(dll/so)や共有ライブラリ(dylib)が提供されている拡張機能では、関係するソースファイルやMakeifileも合わせて提供されています。これらを参考にすると、PrologやC言語で書かれたユーザ定義の機能の追加もAZ-Prologの拡張ライブラリとして利用できるようになります。,ここでは、dll/so/dylibの基本的な作り方について簡単に説明します。,1. ソースプログラムを書く時の注意点,dll/so/dylibを作成するためのソースは、Prolog、C言語、または両方で記述することができます。,Prologで記述する場合、ライブラリのエントリポイントになる述語(他モジュールから呼ばれる述語)はpublic宣言(7-4.(2)参照)されていなければなりません。この場合、これらの述語を組込み述語として登録するための初期化プログラムは、コンパイラazpcがC言語ソースコードを生成する際に自動的に作られます。ファイル名またはモジュール名(7-4.(1)参照)は、この初期化関数の名前の一部になるため、C言語の関数名として妥当なものである必要があります。,C言語で記述する場合は、AZ-Prologの提供するC言語インターフェース(詳細は8章参照)に則って述語(関数)を定義しますが、初期化関数は自ら定義する必要があります。初期化関数の定義については、8-2-2.に解説されています。,2. Makefileの書き方,9-1-3. の一覧表からも分かるように、拡張機能のdll/so/dylibは、1)Prologソースのみで記述されたもの(clp、azedit等)、2)C言語だけで記述されたもの(oniguruma、redis等)、3)Prolog、C言語両方で記述されたもの(odbc等)があります。Prologのソースは、azpcによってC言語に変換された後は、他のC言語で記述されたソースファイルと扱いは同じになります。ここでは1) ~3) の場合について、Windows/Linux/Macそれぞれの環境でdll/so/dylibを生成する場合のMakefileを考えます。ソースファイル名は、Prologで書かれたものはplmodule.pl、C言語で書かれたものはcmodule.cで統一します。また、生成されるdll/so/dylibは、1ファイルのみから生成される場合はソースファイルと同じベースネームとします(plmodule.plからはplmodule.dll/plmodule.soと言う具合)。複数ファイルから生成する場合は、いずれのソースファイル名にも依存しないmydlib.dll/mydlib.so/mydlib.dylibとします。,A.Windows版の場合,Windows環境でのmakeにはnmake.exe(「Microsoft Visual Studio 2013 for Windows Desktop」と一緒にインストールされる)を使用します。,Cコンパイラにはcl.exe(VC++のコマンドラインコンパイラ)を使用し、dllを生成するためにazpdll.libをリンクします。,1) Prologソースファイルからのdllファイル生成Makefile,plmodule.plをazpcでコンパイルしてplmodule.cを生成し、これをCコンパイラでコンパイル・リンクしてplmodule.dllを生成します。,# Makefile Windows版dll生成用(Prologソースから),CC=cl,LIB_PREFIX = %AZProlog%lib,LIB_PREFIX_EXT = %AZProlog%libext,CFLAGS = -nologo -w -O2 -Ox -DWIN32 -DDLL -I. -I"%AZProlog%include",plmodule.dll: plmodule.c,$(CC) $(CFLAGS) plmodule.c /LD "$(LIB_PREFIX)azpdll.lib",plmodule.c: plmodule.pl,azpc -p plmodule.pl /ncc,install:,copy plmodule.dll "$(LIB_PREFIX_EXT)",2) C言語ソースファイルからのdllファイル生成Makefile,cmodule.cからcmodule.dllを生成します。,# Makefile Windows版dll生成用(Cソースから),CC=cl,LIB_PREFIX = %AZProlog%lib,LIB_PREFIX_EXT = %AZProlog%libext,CFLAGS = -nologo -w -O2 -Ox -DWIN32 -DDLL -I. -I"%AZProlog%include",LDLIBS=,cmodule.dll: cmodule.c,$(CC) $(CFLAGS) cmodule.c /LD "$(LIB_PREFIX)azpdll.lib",install:,copy cmodule.dll "$(LIB_PREFIX_EXT)",3) Prolog、C言語の両ソースファイルからのdllファイル生成Makefile,plmodule.pl、cmodule.cからmydlib.dllを生成します。dllの初期化のためにinitiator.cがリンクされていることに注意してください。,initiator.cについては続いて説明しています。,# Makefile Windows版dll生成用(Prolog,Cソースから),CC=cl,LIB_PREFIX = %AZProlog%lib,LIB_PREFIX_EXT = %AZProlog%libext,CFLAGS = -nologo -w -O2 -Ox -DWIN32 -DDLL -I. -I"%AZProlog%include",LDLIBS=,default: mydlib.dll,plmodule.c: plmodule.pl,azpc -p plmodule.pl /ncc,mydlib.dll: cmodule.c plmodule.c initiator.c,$(CC) $(CFLAGS) cmodule.c plmodule.c initiator.c /LD "$(LIB_PREFIX)azpdll.lib",rename cmodule.dll mydlib.dll,install:,copy mydlib.dll "$(LIB_PREFIX_EXT)",$(CC)によって生成されるdllの名前は、ソースファイル並びの先頭のファイル名(ベースネーム、上記の例では、cmodule)と同じになるので、これをmydlib.dllにrenameしています。この部分は、以下の様にinitiator.cの名前をmydlib.cに変えてソース並びの先頭に持って来れば、renameの必要はなくなります。,mydlib.dll: mydlib.c cmodule.c plmodule.c,$(CC) $(CFLAGS) mydlib.c cmodule.c plmodule.c /LD "$(LIB_PREFIX)azpdll.lib",initiator.c(またはmydlib.c)は以下のような内容になっています。AZ-Prologインタプリタのトップレベルでdlib_require(mydlib)を実行すると関数initiate_mydlib()が呼ばれるので、そこから各モジュールの初期化関数が呼ばれることになります。,extern int initiate_plmodule(Frame*);extern int initiate_cmodule(Frame*);__declspec(dllexport) int initiate_mydlib(Frame *Env){ initiate_plmodule(Env); initiate_cmodule(Env);},B.Linux版の場合,Cコンパイラはgccを用い、「-shared -dynamiclib」オプションの指定でso(Shared Object)ファイルを生成します。,1) Prologソースファイルからのsoファイル生成Makefile,plmodule.plをazpcでコンパイルしてplmodule.cを生成し、これをCコンパイラでコンパイル・リンクしてplmodule.soを生成します。,# Makefile ---- Linux版so生成用(Prologソースから),INST_PREFIX = $(AZProlog),CCOPT = -I. -I$(INST_PREFIX)/include,LDOPT = -L$(INST_PREFIX)/lib,CFLAGS = -Wall -O2 $(CCOPT),AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)",AZPC = azpc,CC=gcc,plmodule.so: plmodule.c,$(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c,$(CC) -shared -dynamiclib -o $@ plmodule.o,chmod 644 $@,plmodule.c: plmodule.pl,$(AZPC) -p $< /ncc $(AZPCFLAGS),2) C言語ソースファイルからのsoファイル生成Makefile,cmodule.cからcmodule.soを生成します。,# Makefile ---- Linux版so生成用(Cソースから),CCOPT =,CFLAGS = -Wall -O2 $(CCOPT),CC=gcc,cmodule.so: cmodule.c,$(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c,$(CC) -shared -dynamiclib -o $@ cmodule.o,chmod 644 $@,3) Prolog、C言語の両ソースファイルからのsoファイル生成Makefile,plmodule.pl、cmodule.cからmydlib.soを生成します。初期化のためにinitiator.cがリンクされていることに注意してください。,# Makefile ---- Linux版so生成用(Prolog、Cソースから),INST_PREFIX = $(AZProlog),CCOPT = -I. -I$(INST_PREFIX)/include,LDOPT = -L$(INST_PREFIX)/lib,CFLAGS = -Wall -O2 $(CCOPT),AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)",AZPC = azpc,CC=gcc,default: mydlib.so,plmodule.c: plmodule.pl,$(AZPC) -p $< /ncc $(AZPCFLAGS),mydlib.so: cmodule.c plmodule.c initiator.c,$(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c,$(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c,$(CC) $(CFLAGS) -fPIC -o initiator.o -c initiator.c,$(CC) -shared -dynamiclib -o $@ cmodule.o plmodule.o initiator.o,chmod 644 $@,initiator.cは以下のような内容になっています。AZ-Prologインタプリタのトップレベルでdlib_require(mydlib)を実行すると関数initiate_mydlib()が呼ばれるので、そこから各モジュールの初期化関数が呼ばれることになります。,extern int initiate_plmodule(Frame*);,extern int initiate_cmodule(Frame*);,int initiate_mydlib(Fram *Env){,initiate_plmodule(Env);,initiate_cmodule(Env);,},C.Mac版の場合,Cコンパイラはgccを用い、「-dynamiclib」オプションの指定でdylib(共有ライブラリ)ファイルを生成します。,1) Prologソースファイルからのdylibファイル生成Makefile,plmodule.plをazpcでコンパイルしてplmodule.cを生成し、これをCコンパイラでコンパイル・リンクしてplmodule.dylibを生成します。,# Makefile ---- Mac版dylib生成用(Prologソースから),INST_PREFIX = $(AZProlog),CCOPT = -I. -I$(INST_PREFIX)/include -fno-strict-aliasing,LDOPT = -L$(INST_PREFIX)/lib,CFLAGS = -Wall -Wno-deprecated-declarations -O2 -DMAC $(CCOPT),AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)",AZPC = azpc,CC=gcc,plmodule.dylib: plmodule.c,$(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c,$(CC) -dynamiclib -Wl,-undefined -Wl,dynamic_lookup -o $@ plmodule.o -lc,chmod 644 $@,plmodule.c: plmodule.pl,$(AZPC) -p $< /ncc $(AZPCFLAGS),2) C言語ソースファイルからのdylibファイル生成Makefile,cmodule.cからcmodule.dylibを生成します。,# Makefile ---- Mac版dylib生成用(Cソースから),CCOPT =,CFLAGS = -Wall -Wno-deprecated-declarations -O2 -DMAC $(CCOPT),CC=gcc,cmodule.dylib: cmodule.c,$(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c,$(CC) -dynamiclib -Wl,-undefined -Wl,dynamic_lookup -o $@ cmodule.o -lc,chmod 644 $@,3) Prolog、C言語の両ソースファイルからのdylibファイル生成Makefile,plmodule.pl、cmodule.cからmydlib.dylibを生成します。初期化のためにinitiator.cがリンクされていることに注意してください。,# Makefile ---- Mac版dylib生成用(Prolog、Cソースから),INST_PREFIX = $(AZProlog),CCOPT = -I. -I$(INST_PREFIX)/include,LDOPT = -L$(INST_PREFIX)/lib,CFLAGS = -Wall -Wno-deprecated-declarations -O2 -DMAC $(CCOPT),AZPCFLAGS = /message /s_verbos /cc $(CC) /ccopt "$(CCOPT)" /link_opt "$(LDOPT)",AZPC = azpc,CC=gcc,default: mydlib.dylib,plmodule.c: plmodule.pl,$(AZPC) -p $< /ncc $(AZPCFLAGS),mydlib.dylib: cmodule.c plmodule.c initiator.c,$(CC) $(CFLAGS) -fPIC -o cmodule.o -c cmodule.c,$(CC) $(CFLAGS) -fPIC -o plmodule.o -c plmodule.c,$(CC) $(CFLAGS) -fPIC -o initiator.o -c initiator.c,$(CC) -dynamiclib -Wl,-undefined -Wl,dynamic_lookup -o $@ cmodule.o plmodule.o initiator.o -lc,chmod 644 $@,initiator.cは以下のような内容になっています。AZ-Prologインタプリタのトップレベルでdlib_require(mydlib)を実行すると関数initiate_mydlib()が呼ばれるので、そこから各モジュールの初期化関数が呼ばれることになります。,extern int initiate_plmodule(Frame*);,extern int initiate_cmodule(Frame*);,int initiate_mydlib(Frame *Env){,initiate_plmodule(Env);,initiate_cmodule(Env);,},3. Makeの仕方と動作確認,1) Makeの仕方,Windowsの場合は「VS2013 x64(32ビットならx86) Cross Tools コマンドプロンプト」(7-1参照)上でnmake.exeを実行します。このコマンドプロンプトでは、nmake.exeやcl.exeをコマンドラインで実行するのに必要な環境設定が全てされています。Linux版またはMac版ならシェルターミナルからmakeを実行します。ならシェルターミナルからmakeを実行します。4.2で説明したMakefileであれば、いずれも引数(ターゲット指定)なしで実行します。生成されたdll/so/dylibファイルはnmake.exeまたはmakeを実行したカレントディレクトリに置かれます。,2) 動作確認,Windows、LinuxまたはMacいずれの場合も、AZ-Prologを起動して述語 dlib_require/1 でdll/so/dylibを呼び出します。dll/so/dylibファイルはAZ-Prologを起動したディレクトリにあるものとし、仮にmylib.dllまたはmylib.soまたはmylib.dylibとします。yesと表示されれば無事ロードされ、初期化が完了したことになります。,| ?-dlib_require('./mydlib').,yes,後は、実装した述語を実行して、正しく呼び出されることを確認してください。,上記の例のように、dll/so/dylibをパスで指定することもできますが、dll/so/dylibのサーチパス(組込述語 dlib_get_searchi_path/1 で確認ができます)上に置けば、以下のように名前で指定することができます。,| ?-dlib_require(mydlib)."}); htmllist.push({"file":"manuals/manual_function_summary.html#func_5","title":"9-1-5.拡張機能のスタティックリンク方法","text":"9-1-5.拡張機能のスタティックリンク方法,拡張機能をスタティックリンクして、コンパイルされた実行モジュールに予め組込んでしまうこともできます。この場合は1ファイルだけで実行可能なので、可搬性は高くなります。,例として、AZ-Prologインタプリタにユーザ定義のpmodule.plとエディタAzEditをスタティックに組み込む場合を考えます。,1) 拡張機能のソースファイルを一緒にコンパイル・リンクする方法,azedit.plと言うソースファイルが提供されているので、これを一緒にコンパイル・リンクする方法は以下の通りです。,Windows,> azpc -p plmodule.pl /i /e myprolog /static "%AZProlog%¥system¥ext¥azedit¥azedit.pl",Linux,$ azpc -p plmodule.pl /i /e myprolog /static ${AZProlog}/share/azprolog/system/ext/azedit/azedit.pl,Mac,$ azpc -p plmodule.pl /i /e myprolog /static ${AZProlog}/share/azprolog/system/ext/azedit/azedit.pl,2) スタティックリンクライブラリをリンクする方法,Linux版では拡張機能のsoファイル、Mac版では拡張機能のdylibファイルのみならず、スタティックリンクライブラリも提供されており、その生成方法も各拡張機能のMakefileに公開されています。Windows版では現時点で拡張機能のスタティックリンクライブラリは提供されておりません。,ここでは、Linux版またはMac版について、提供されたスタティックリンクライブラリをリンクした実行モジュールを生成する方法を解説します。,例として、エディタAzEditを組み込む方法は以下のようになります。AzEditのスタティックライブラリはlib_azedit.aなので、"-L ${AZProlog}/lib/azprolog/ext -l_azedit"で指定しています。,    $ azpc -p plmodule.pl initiator.c /i /e myprolog /link_opt2 "-L ${AZProlog}/lib/azprolog/ext -l_azedit" /static,ここでinitiator.cは、以下の通りです。,extern int initiate_azedit(Frame*);,void initiate_initiator(Frame *Env){,initiate_azedit(Env);,},実行プログラムを生成する際、azpcはuserfile.cと言うファイルを作成して、この中に各モジュールの初期化関数の呼び出しを並べた関数user_file()を自動生成します(8-2-2参照)。但し、ライブラリの初期化関数呼び出しは現時点では自動的には書かれないので、手書きしてやる必要があります。initiator.cはリンクするライブラリの初期化関数呼び出しを並べたファイルです。このファイルはazpcによって1つのモジュールと見なされ、このモジュールの初期化関数(initiate_initiator())の呼び出しはuserfile.cに書かれるので、この関数内に必要なライブラリの初期化関数呼び出しを並べて置けばよいことになります。,但し、拡張機能ライブラリが、更に外部ライブラリを参照している場合は、それらもリンクしなければなりません。,外部ライブラリが必要になる拡張機能の例として、Redisクライアントを組み込む方法は以下のようになります。外部ライブラリは「/lib hiredis」で与えています。,  $ azpc -p plmodule.pl initiator.c /i /e myprolog /link_opt2 "-L ${AZProlog}/lib/azprolog/ext -l_redis" /static /lib hiredis,iniitiator.cはazeditの場合と同様ですが、以下の通りです。,extern int initiate_redis(Frame*);,void initiate_initiator(Frame *Env){,initiate_redis(Env);,},以下に、拡張機能をスタティックリンクする際に必要となるライブラリの指定方法をまとめておきます。,拡張機能スタティックリンク時の必要ライブラリ,機能拡張,拡張機能スタティックライブラリ,外部ライブラリ,制約論理 clp,"-L ${AZProlog}/lib/azprolog/ext -l_clp",なし,鬼車 oniguruma,"-L ${AZProlog}/lib/azprolog/ext -l_oniguruma",/lib onig,めかぶ mecab,"-L ${AZProlog}/lib/azprolog/ext -l_mecab",/lib mecab,ソケット socket,"-L ${AZProlog}/lib/azprolog/ext -l_socket",なし,               socket_ssl,"-L ${AZProlog}/lib/azprolog/ext -l_socket_ssl",/lib ssl /lib crypto,               websock,"-L ${AZProlog}/lib/azprolog/ext -l_websock",/lib websockets,Redis redis,"-L ${AZProlog}/lib/azprolog/ext -l_redis",/lib hiredis,エディタ azedit,"-L ${AZProlog}/lib/azprolog/ext -l_azedit",なし,*鬼車の場合、提供サンプルoniguruma.plで動作確認をする場合、${AZProlog}/share/azprolog/system/pl/utility.pl,が必要になります。このファイルもリンクするか、コンサルトしてから確認してください。"}); htmllist.push({"file":"manuals/manual_feature_structure.html#Outline","title":"9-2-1.概要","text":"9-2-1.概要,AZ-PrologでHPSGなどの単一化文法を容易に実装するため、データ型として素性構造型を導入しました。,ICOTで開発されたCU-Prologを参考に仕様検討、動作検証をおこないましたが、次の点で異なります。,・セミコロンによる制約記述は取り入れておりません。,・変数に制約条件を直接記述するシンタックスを取り入れました。変数間の関係、チェックが簡素化できます。,・差分リストに似た素性構造の差分表現を導入しました。 ,Version9.5で型付素性構造型を導入しました。 ,型付素性構造とは、型の概念を素性構造に導入したものです。,型は継承関係による階層構造を備えています。型を利用することで、豊富な情報を簡潔に、適切な抽象化の水準で表現できます。,プログラムをコンサルトした時点で型推論および型検査が行われるため、値の整合性を点検することができ、バグを早期発見できる利点があります。実行時には、互いにマッチングする型のみに探索範囲を絞ることができるため、型の導入はプログラムの高速化にも寄与します。,型付素性構造を利用するためには、前もって型と素性、および型どうしの継承関係を適切に設計しておく必要があります。,型付素性構造の処理系の仕様は LiLFeS 、およびその背景となる Bob Carpenter, The Logic of Typed Feature Structure を参考にしています。,LiLFeS と AZ-Prolog の仕様の違いについては、9-2-7. LiLFeS と AZ-Prolog の型付素性構造の違いを参照してください。,素性構造モードを切り替えることで、型のない素性構造型と型付素性構造型を使い分けることができます。,素性構造型,<素性構造>を取り扱うモードのとき(default) 中括弧で括られた任意の個数の<素性と値の対>のみを要素とする並びを<素性構造>とします。,空を除き、<素性と値の対>を一つも要素としない場合、従来構造として扱います。混在はエラーとなります。,<例>,素性構造の例,{} 空の素性構造,{ 氏名:山田太郎,生年月日:{年:1951,月:5,日:26},子供:[花子,一郎,二郎] ,趣味:X },{ 品詞:動詞 |Else } 差分表現,素性構造でない従来型の例,{write(X),nl},エラーとなる例,{ a:b,a:z } 同一素性が含まれている,{ a:b,x:z,A } <素性と値の対>と素性以外の項とが混在している,{ a:b,Z:z } 素性がアトムでない,<素性と値の対>,・'素性(アトム)' + '区切り記号(オペレータ)' + 素性値 で表現します。,<素性>,・素性は複合項のファンクタがアトムであることを必須とするのと同様に、アトムでなくてはなりません。,・素性は素性構造の同一レベルではユニークでなければなりません。,・素性値が素性構造をとり、階層が異なる場合は親側と同一の素性があってもよいでしょう。,<素性値>,・素性値は素性構造を含む任意の項です。,<区切り記号>,・区切り記号はデフォルトでは,':'であるが、変更することができます。(下記:fs_delimiter/2),区切り記号を変更し、'/'とすれば、Cu-Prolog,CILなどのICOT標準表記となります。,ただし、区切り記号 '/ ' はyfxなので、a/b/c などでは/(/(a,b),c)となり素性名がアトムにならないので注意しましょう。,また、op述語で '/ ' をxfyに変更してしまうと、数値計算に支障をきたすので注意してください。,<DCG補強項などとの混在>,<素性と値の対>を一つも含まない中括弧の構造は、従来と同様に扱われることによりDCGの補強項も問題なく混在可能です。,<例>,is_adult(A,{level:child}):- A,is_adult(A,{level:adult}).,a(X) --> { X={age:A#is_adult(A,X)} },b(X).,b(X) --> { write(end),nl },[end].,展開: a(X,S,T) :- freeze(A,is_adult(A,X)),X={age:A}, b(X,S,T).,展開: b(X,[end|T],T):-write(end),nl.,|?-X = {age:30},a(X,[end],[]).,end,X = {age:30,level:adult},yes,型付素性構造型,素性構造に型概念を導入したデータ構造を型付素性構造と呼びます。素性構造モードが型付素性構造モードの時に利用可能です。,型を導入することで概念の階層構造を表現することができます。型は型名を表すアトムの後方に '&' 演算子を付与して表記されます。,型付素性構造は,型&素性構造,という書式で表されます。素性構造の部分に関する書式は型のない素性構造と共通です。素性構造内部の素性値も型を持つため、入れ子構造をとることができます。,型を導入することで、階層を持った概念の記述や、概念どうしの関係性に関する処理を簡潔に行うことができます。型が存在しない場合、概念の階層関係を冗長な素性構造を用いて表現する必要があったり、概念間の推論手順を明示的に記述する必要があったりするなど、プログラムが煩雑になることがありますが、型を導入することでこれを簡単に表現し処理することができます。,また、型と素性、素性と素性値に対して制約条件を課すことができ、コンサルト時に型推論、型検査が行われます。このため、プログラムを簡潔で安全なものにすることができます。,型付素性構造の利用にあたっては、前もって型の定義、および型と素性の関係について定義を行っておく必要があります。これは以下の構文を用いて行います。,型 <- [型1, 型2, ...] + [素性1:素性1の型, 素性2:素性2の型, ...].,左辺の型は右辺の 型1, 型2, ... を継承した型として定義されます。ある型を基準として、それ自身または先祖にあたる型を supertype と呼び、それ自身または子孫にあたる型を subtype と呼びます。,型1, 型2, ... および 素性1の型, 素性2の型, ... は、これよりも前の行であらかじめ定義しておく必要があります。,定義された型がとることのできる素性は、親の型の素性および 素性1, 素性2, ... に限られ、それ以外の素性を持つことはできません。また、素性1, 素性2, ... がとることのできる値は、それぞれ 素性1の型, 素性2の型, ... の subtype に限られます。,組み込み型として bot, list, string, atom, integer, float が用意されています。bot はすべての型の supertype となる特殊な型であり、残りはそれぞれリスト、文字列、アトム、整数、実数を指定する際に用いられます。,詳しくは 9-2-6.型付素性構造の詳細 を参照してください。"}); htmllist.push({"file":"manuals/manual_feature_structure.html#Section02","title":"9-2-2.組込述語","text":"9-2-2.組込述語,fs_mode/2, fs_delimiter/2, fstructure/1,type_supertypes/2,type_subtypes/2,type_struct/4が新規に追加されています。また、listing/0,s_new/0,consult/1,reconsult/1 に関しては、型付素性構造モード特有の拡張が行われています。,組込述語,fs_mode(?I1,+I2),I1, I2とも、0, 1, 2 のいずれかの整数,I1 現在の素性構造モード,I2 設定する素性構造モード,0: 素性構造型を利用しません。(従来と同じ。V8までとの互換性のために用意されています。),1: (型のない) 素性構造型を利用します。,2: 型付素性構造型を利用します。,初期値は 1 に設定されています。,素性構造型を利用せず、かつ素性構造型に抵触する書式の従来プログラムがある場合には、素性構造モードを 0 にすることで従来のシンタックスを適用できます。,コンサルトしたプログラム中に型定義が存在する場合、素性構造モードは自動的に 2 に切り替わります。,<例>,:- fs_mode(_,0).,fs_delimiter(?A1,+A2),A1 : 現在の素性名と素性値の組を区切る中置きオペレータ名がユニファイされます。,A2 : 設定する新しい素性名と素性値の組を区切る中置きオペレータ名,中置きオペレータでない場合は同時にオペレータ宣言をしておきます。,初期値は ":" 結合値=550,xfy。,<注意>,本述語は、CU-Prologのソースを利用するなど特別に必要な場合、そのソースファイルの先頭に切り替えを宣言します。その際、ユーザーの作成するプログラム中に現れる区切り記号もこれに統一しておかねばなりません。,動的、頻繁に切り替えるのは混乱と誤動作をまねくので慎むべきです。,<例>,:- fs_delimiter(_,!).,:- op(550,xfy,!).,a({a!b,c!d}).,fstructure(+Term),Term : 調べたい項,Termが素性構造型であるときのみ成功します。,<例>,|?- X={a:{b:bb,c:cc}},fstructure(X).,yes,type_supertypes(+A,-L),A: 型名,L: 型 A の supertype の名前から成るリスト, ,型付素性構造モードで用います。,<例>,% コンサルトする型定義ファイル (以降の例で共通),三角形 <- [bot] + [色:atom].,二等辺三角形 <- [三角形].,直角三角形 <- [三角形].,直角二等辺三角形 <- [二等辺三角形, 直角三角形].,正三角形 <- [二等辺三角形].,| ?- type_supertypes(直角二等辺三角形, X).,X = [直角二等辺三角形,二等辺三角形,直角三角形,三角形,bot],yes,type_subtypes(?A,-L),A: 型名,L: 型 A の subtype の名前から成るリスト, ,型付素性構造モードで用います。A が特定の型名の場合は、その型の subtype が L に出力されます。A が変数の場合には存在する型を順に A と単一化していき、そのたびに対応する subtype が L に出力されます。,<例>,|?- type_subtypes(二等辺三角形, X).,X = [二等辺三角形,直角二等辺三角形,正三角形],yes,type_struct(?A,-L1,-L2,-L3),A: 型名,L1: 型 A の直接の親から成るリスト (型定義における右辺の型),L2: 型 A の supertype の名前から成るリスト,L3: 型 A と関連付けられた素性と素性値の型名から成るリスト, ,型付素性構造モードで用います。A が特定の型名の場合は、対応する L1, L2, L3 が出力されます。 A が変数の場合には存在する型を順に A と単一化し、そのたびに対応する L1, L2, L3 が出力されます。, ,<例>,| ?- type_struct(直角二等辺三角形, X, Y, Z).,X = [二等辺三角形,直角三角形],,Y = [直角二等辺三角形,二等辺三角形,直角三角形,三角形,bot],,Z = [色:atom],yes,listing (型付素性構造に関する拡張),型付素性構造モードにおいて listing/0 述語を実行すると、先頭に型情報が次の書式で出力されます。,型 <- [supertype1, supertype2, ...] + [素性1:素性1の型, 素性2:素性2の型, ...].,supertype1, supertype2, ... に関しては直接の継承元だけではなく、型階層でたどれるすべての supertype が出力されます。素性および素性値の型についても、型定義文でその型に関連付けたものだけでなく、 supertype 経由で継承される素性および素性値の型も含めてすべて出力します。,型情報に引き続きプログラムが出力されます。これは型付素性構造モード以外での動作と同じです。,s_new (型付素性構造に関する拡張),型付素性構造モードでは、s_new/0によってユーザ述語だけでなく型定義の情報もすべて消去します。,consult(+A) (型付素性構造に関する拡張),型定義を読み込むと、自動的に素性構造モードが型付素性構造モードに変化します。またプログラムを読み込む際に型推論を行う点が通常のコンサルトと異なります。,reconsult(+A) (型付素性構造に関する拡張),型定義を全て消去してからリコンサルトを行います。述語の読み込みに関しては通常のリコンサルトと同様に、同じ述語がすでに存在する場合は古い定義を消去してからコンサルトを行います (その際に型推論が行われます) 。,リコンサルトするプログラムに登場しない述語に関しては消去されずに以前の定義が残りますが、これらの述語は以前の型定義に基づいて型推論されたままであることに注意が必要です。これらの述語を利用するとプログラムの整合性に関して問題が発生する可能性があります。安全のため、 s_new/0を利用してプログラムをすべて消去したうえでリコンサルトすることを推奨します。"}); htmllist.push({"file":"manuals/manual_feature_structure.html#Section03","title":"9-2-3.素性構造のユニフィケーション","text":"9-2-3.素性構造のユニフィケーション,素性構造モード (述語 fs_mode/2を参照) によって、ユニフィケーションの振る舞いが異なります。,素性構造型を利用しないモード (モード 0),通常のユニフィケーションの原則に従います。,| ?- X = {Y, c:d}, X = {a:b, Z}, write(X), nl.,{a:b,c:d},X = {a:b,c:d},,Y = a:b,,Z = c:d,yes,| ?- X = {a:b, c:d}, X = {c:d, a:b}, write(X), nl.,no,| ?- X = {a:b, c:d}, X = {c:d, e:f}, write(X), nl.,no,型のない素性構造型モード (モード 1),デフォルトのモードです。,・素性構造は素性構造または変数とのみユニフィケーションします。他の型とでは失敗します。,・素性構造1と素性構造2のユニフィケーションにおいて、,(1)1に含まれる素性が2の同一階層に含まれるとき、その素性値同士を再帰的にユニフィケーションします。,(2)1に含まれる素性が2の同一階層に含まれないとき、また2に含まれる素性が1の同一階層に含まれないとき,含まれないほうの素性構造にその<素性と値の対>が追加され、1と2は同一構造となります。,(3)リストを素性構造に見立てたユニフィケーションと異なり、要素の出現順位、要素数に関わりなく単一化が可能です。,<例>,% 素性を指定しての素性値の取り出し,|?- X= {a:S,b:c,c:d},X={c:Z}.,X = {a:S,b:c,c:d},Z = d,yes,% 注意:含まれない素性での素性値の取り出しは追加になる,|?- X= {a:S,b:c,c:d},X={q:Z}.,X = {a:S,b:c,c:d,q:Z},yes,% 素性値のユニフィケーション、含まれないの追加,|?- X= {a:Z,b:c},Y={a:3,d:e},X=Y.,X = {a:3,b:c,d:e},Y = {a:3,b:c,d:e},Z = 3,yes,% 素性値が異なりFailする,|?- X= {a:{a:b,c:c},b:c},Y={a:3,d:e},X=Y.,no,% 素性値に対しても再帰的に素性構造ユニフィケーションが適用される,|?- X={a:{b:bb}},Y={a:{c:cc}},X=Y.,X = {a:{b:bb,c:cc}},,Y = {a:{b:bb,c:cc}},yes,% Heap上の素性構造とのユニフィケーション(1),a({}).,|?- X={b:bb},a(X).,X = {b:bb},yes,% Heap上の素性構造とのユニフィケーション(2),b({c:cc}).,|?- X={b:bb},b(X).,X = {b:bb,c:cc},yes,% Heap上の定義は変わらない,|?- listing.,a({}).,b({c:cc}).,yes,% 素性構造の差分表現,% (1)ある素性構造(X)から所定の素性を含まない素性構造(T)の抽出,?- X={a:b,c:d},X={c:d|T}.,T = {a:b},X = {a:b,c:d},yes,?- X={a:b,c:d},X={q:m|T}.,T = {a:b,c:d},X = {q:m,a:b,c:d},yes,% (2)ある素性構造(T)を差分とする素性構造(X)の表現(生成),?- T={a:b},X={b:c|T}.,X={b:c,a:b},,T={a:b},yes,% (3)切り出された差分は、束縛の有無に関わらず別素性構造となり切り出し元に影響を与えない,?- X={b:c|T},T={a:b}.,X={b:c},T={a:b},yes,?-X={a:b,c:d},X={c:d|T},T={e:f},X={c:d,a:b},T={a:b,e:f},yes,% 要素の削除,rm_cat({cat:_|T},T).,|?- rm_cat({phon:walk,cat:verb,sc:[noun]}, Else).,Else = {phon:walk,sc:[noun]},yes,% 構造の変更,change_ha_to({は格:H,と格:T | Else },{は格:T,と格:H | Else }).,|?- change_ha_to({と格:ジョンレノン,は格:オノヨーコ, head:結婚した },Ans).,Ans = {は格:ジョンレノン, と格:オノヨーコ, head:結婚した },yes,<注意> 素性構造の差分表現を用いる際、差分の箇所に置かれた変数を節の頭部と本体にまたがってマッチさせることはできません。そのような記述を行った場合、動作結果は未保証です。,% (不適切な例) 差分 L が頭部と本体の両方に登場するが、これらはマッチしない,p(X,{a:Z|L}) :- X = {a:Z|L}.,| ?- p({b:bb,a:aa},Y).,Y = {a:aa},yes,% (適切な例) 差分 L が本体の 2 か所に現れる。これはマッチする,q(X,Y) :- X = {a:Z|L}, Y = {a:cc|L}.,| ?- q({b:bb,a:aa},Y).,Y = {a:cc,b:bb},yes,% (適切な例) 差分 L が頭部の 2 か所に現れる。これもマッチする,r({a:_|L},{a:cc|L}).,| ?- r({b:bb,a:aa},L).,L = {a:cc,b:bb},型付素性構造型モード (モード 2),まず型どうしの単一化が試みられ、それに成功すると、引き続いて素性構造の単一化が行われます。素性構造の内部についても、再帰的に同様の処理が繰り返されます。素性構造自体の単一化の仕組みはモード1と同じです。,型の単一化とは、両方の型の subtype の中で最も一般的な型を見つけることです。次のような型定義においては、a と b を単一化すると b に、 b と c を単一化すると d になります。b と e は単一化することができません。,% 型定義,a <- [bot] + [f:atom, g:atom].,b <- [a].,c <- [a].,d <- [b, c].,e <- [a].,この型定義をもとにして型付素性構造の単一化を行ったのが以下の例です。,| ?- X = a&{p:s}, X = a&{q:t}. % モード 1 でも 2 でも同じ結果,X = a&{p:s, q:t}.,yes,| ?- X = b&{p:s}, X = c&{q:t}. % モード 1 だと b も c も単なるアトムなので失敗する,X = d&{p:s, q:t}.,yes,| ?- X = b&{p:s}, X = e&{q:t}. % モード 2 でも型の単一化ができなければ失敗する,no,詳しくは、9-2-6.型付素性構造の詳細 を参照してください。"}); htmllist.push({"file":"manuals/manual_feature_structure.html#Section04","title":"9-2-4.素性構造型のメタ述語適用","text":"9-2-4.素性構造型操作のユーティリティ(コンパイル組込述語),ソース ($InstallDir)/system/pl/fs_utility.pl,< 1: 素性と値の対 と 素性,素性値の相互変換>,fs_av/3,(1)Arg1の,からArg2:素性,Arg3:素性値へ分解,(2)Arg2:素性,Arg3:素性値 から<素性と値の対>を生成します。,|?- fs_av(attr:value,A,V).,A = attr,,V = value,yes,|?- fs_av(AV,attr,value).,AV = attr:value,yes,< 2:素性構造とコア構造(','/2)の相互変換 >,fs_body/2,(1) Arg1:素性構造からArg2:コア構造を取り出します。,(2) Arg2:コア構造をArg1:素性構造へ変換します。,|?- fs_body({a:bb},Core).,Core = (a:bb,_),yes,|?- fs_body(FS,(a:bb,_)).,FS = {a:bb},yes, ,< 3:動的に素性構造を生成します >,fs_new/3,Arg1を素性名、Arg2を値とする素性構造を生成し、Arg3に単一化します。,|?- fs_new(a,aaa,X).,X = {a:aaa},yes,|?- Q=q,fs_new(Q,S,X).,X = {q:S},yes,|?- X={a:b},Q=q,fs_new(Q,S,X).,X = {a:b,q:S},yes, ,< 4:素性構造の全要素をリストに展開します >,fs_list/2,(1)素性構造(Arg1)の全要素をリスト(Arg2)に展開します。,(2)リスト(Arg2)を素性構造(Arg1)に変換します。,|?- fs_list({category:noun_phrase,number:singular},L).,L = [category:noun_phrase,number:singular],yes,|?- fs_list(FS,[category:noun_phrase,number:singular]).,FS = {category:noun_phrase,number:singular},yes,|?-X={a:bb,c:dd},fs_list(X,L),fs_list(X,[e:qq]).,X = {a:bb,c:dd,e:qq},,L = [a:bb,c:dd],yes, ,< 5:ある素性:値が素性構造に含まれているか調べます >,fs_member/2,Arg1調べる要素側の変数は単一化するが リストの要素を調べるmember/2と異なり、Arg2素性構造側は単一化はしません。単一化したい時は、後述のpvalue/3を利用します。,|?- fs_member(number:X,{category:noun_phrase,number:singular}).,X = singular,yes,| ?- fs_member(number:X,{category:noun_phrase,number:Y}).,X = X_20, Y = Y_22,yes,| ?- fs_member(number:d,{category:noun_phrase,number:X}).,no,| ?- fs_member(number:X,{category:noun_phrase,number:{p:Y}}).,X = {p:_20}, Y = Y_22,yes,| ?-fs_member(a:{b:bb,c:X},{a:{c:1,b:bb}}).,X = 1,yes, ,< 6:素性構造のコピー >,fs_copy/2,Arg1の素性構造を制約情報を含めた同一構造にコピーしArg2に単一化します。,|?- s_constraints_mode(_,on).,yes,|?- X={a:P#(P=A),b:A},fs_copy(X,Y),Y={a:aa}.,X = {a:_75,b:A_63},,P = _75,,A = A_63,,Y = {a:aa,b:aa},yes, ,< 7: 素性構造の結合 >,fs_append/3,二つの素性構造を元の素性構造は変えず結合した新しい素性構造を生成しArg3に単一化します。,|?- X={a:S,b:bb},Y={b:Q,e:S},fs_append(X,Y,Z).,X = {a:S_62,b:bb},,Y = {b:Q_70,e:S_62},,Z = {b:bb,e:_160,a:_160},yes,単純に二つの素性構造を結合するだけなら、素性構造のユニフィケーションでよいでしょう。,|?- X={a:aa},Y={b:bb},X=Y.,X= {a:aa,b:bb},,Y= {a:aa,b:bb},yes, ,< 8:任意個の素性構造を結合 >,fs_appends/2,複数の素性構造を結合した新しい素性構造を生成しArg2に単一化します。,|?-X={a:S,b:bb},Y={b:Q,e:Q},fs_appends([X,Y,{a:Q}],D).,X = {a:S_70,b:bb},,S = S_70,,Y = {b:Q_78,e:Q_78},,Q = Q_78,,D = {a:bb,b:bb,e:bb},yes, ,< 9:素性構造に含まれる素性リストをArg2に単一化する >,pnames/3 (Cu-Prolog 組込互換),Arg1を素性名、Arg2を値とする素性構造を生成し、Arg3に単一化します。,|?- pnames({a:aa,b:bb,c:cc},L).,L = [a,b,c],yes, ,< 10:素性構造(Arg1)に含まれる素性(Arg2)の値をArg3に単一化します >,pvalue/3 (Cu-Prolog 組込互換),相当する素性がない場合にはfail します。,|?- pvalue({a:aa,b:bb,c:cc},b,V).,V = bb,yes,|?- pvalue({a:aa,b:bb,c:cc},q,V).,no,|?- FS={a:aa,b:bb,c:cc,q:C}, pvalue(FS,q,1).,FS = {a:aa,b:bb,c:cc,q:1},,C = 1,yes,% 深い階層の素性へのアクセスの簡略表現,|?- pvalue({a:aa,b:{d:dd,q:{f:bb}},c:cc},b:q:f,V).,V = bb,yes,< 11:素性構造をAVM形式で表示します >,fs_writeAVM/1,| ?- fs_writeAVM({ 氏名:山田太郎,生年月日:{年:1951,月:5,日:26},趣味:X }).,|~ ~|,| 氏名: 山田太郎 |,| 生年月日:|~ ~| |,| | 年:1951 | |,| | 月:5 | |,| | 日:26 | |,| |_ _| |,| 趣味: X_56 |,|_ _|,X = X_56,yes"}); htmllist.push({"file":"manuals/manual_feature_structure.html#Section05","title":"9-2-5.素性構造型操作のユーティリティ(コンパイル組込述語)","text":"9-2-5.素性構造型を使った構文解析プログラム例,ICOTで開発された CU-Prologに付属のサンプルプログラム、シンプルHPSGをAZ-Prolog用に書き換えたものが,sample/nluに格納されていますので、これを動かしてみましょう。,%%%%%%%%%% hpsg.pl %%%%%%%%%%%%%%,:- ['tree.pl']. % CU-Prologの組込述語 tree/1 をAZ-Prolog用に書いたもの,p(Sentence):-,parse0(Cat,H,Sentence,[]),,nl,tree(H),nl,write('category= '),write(Cat),nl.,parse0(MCat,MHist,Str,Rest):-,lookup(Str,SubStr,Cat,Hist),!,,parse1(Cat,Hist,MCat,MHist,SubStr,Rest).,parse1(Cat,H,Cat,H,Str,Str).,parse1(LCat,LHist,GCat,GHist,Str,Rest):-,psr(LCat,RCat,MCat,RN),,parse0(RCat,RHist,Str,SubStr),,parse1(MCat,t(t(MCat,RN,[]),LHist,RHist),GCat,GHist,SubStr,Rest).,% LeftCategory RightCategory MotherCategory,psr({head/H, sc/[RH|PSC],ph/LP},{head/RH,sc/[],ph/RP}, {sc/PSC,head/H,ph/PP},1):-append(LP,RP,PP).,psr({head/RH,sc/[], ph/LP},{head/H,sc/[RH|PSC],ph/RP},{sc/PSC,head/H,ph/PP},2):-append(LP,RP,PP).,lookup([Word|X],X,{ph/[Word],head/Cat,sc/SC},t(Cat,[Word],[])) :-dict(Word,Cat,SC).,dict(mary, noun, []).,dict(john, noun, []).,dict(meets,verb,[noun,noun]).,% : 以下の単語定義略,%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%,<実行例>,>prolog,|?- consult('hpsg.pl').,yes,|?- p([mary,meets,john]).,{sc/[],head/verb,ph/[mary,meets,john]}---1,|--{sc/[noun],head/verb,ph/[mary,meets]}---2,| |--noun---[mary],| |__verb---[meets],|__noun---[john],category= {sc/[],head/verb,ph/[mary,meets,john]},yes,9-2-6.型付素性構造の詳細へ続きます。"}); htmllist.push({"file":"manuals/manual_clp.html#clp","title":"9-3-1.概要","text":"9-3-1.概要,制約論理とは、従来の述語論理の枠組みに制約と言う知識表現とその解消(充足)による問題解決の考え方を導入したものです。,このパラダイムを実現するために、AZ-Prologのユニフィケーションの仕組みを拡張しました。具体的には、変数が束縛(値を持つこと)された時に初めてゴールが起動される仕組み(遅延実行機構)や、束縛された際に変数が取り得る値領域(領域制約)に対するチェックがなされ結果がユニフィケーションの真偽に反映される仕組み等です。遅延実行ゴールや変数の値領域の設定には freeze/2 、 put_clp_area/2 等の組込述語が提供されています。その上にPrologによる制約解消系の構築を行いました。,制約解消系は未完成です。順次充実を図っていきますのでご協力ください。,ソースファイルやRead項の変数に直接制約マクロ記述を含めることができます。,マクロ記述は制約をおこなう変数に中置きオペレータ "#" で接続した述語、または領域制約リスト、,または()内に並べたそれらの複合です。,本機能はRedisなどを辞書として用い、辞書引きしたときに辞書構造に制約を含めることによって記述を,簡素化することを目的に開発されました。,この機能はVer9で追加されました。詳細は後述する A.基本組込述語 (10)s_constraints_mode/2,(12)macro_consult/1を参照してください。,<例>,a(X#[1..10],Y#(X=Y,[5..20])).,処理系の制約論理拡張は 『制約論理プログラミング (知識情報処理シリーズ 別巻2)共立出版(株)』を参考にしました。"}); htmllist.push({"file":"manuals/manual_clp.html#clp_2","title":"9-3-2.組込述語","text":"9-3-2.組込述語,組込述語は、AZ-Prolog本体に組み込まれた基本組込述語と、dll/soの形で提供される拡張ライブラリ組込述語の2種類があります。,後者は基本組込述語を用いて制約解消系をProlog言語で記述したものです。,A.基本組込述語,(1)決定性述語: clpvar/1 ,引数が制約変数のときに成功します。,(2)決定性述語: freeze/2 ,変数が値を持った時に起動される遅延実行ゴールを設定します。,詳細は述語リファレンスをご参照ください。,ある変数が値を持った時に実行されるゴールは、同一変数に対して順次 freeze/2 で追加することができますが、遅延実行時においては決定性、すなわちゴール(列)の最後にカットオペレータがついたものになります。,デバッグモードで起動し、ある変数が値をもったときtraceを開始させるspyの変形(下記の例)のように、制約解消系以外の用途でも使うことができます。,<例>,| ?-debug.,|| ?-freeze(X,trace),go(X). % go(X) の実行の経過で、X が値を持ったときにtrace が開始される,(3)決定性述語: frozen/2 ,変数(第1引数に指定)に設定さている遅延実行ゴールを第2引数とユニファイします。遅延実行機構はこの述語により遅延実行ゴールを取得します。また設定内容の確認にも用いることができます。,詳細は述語リファレンスをご参照ください。,(4)決定性述語: put_clp_area/2 ,変数に値領域(領域制約)を設定します。既に値領域が設定されている場合はANDで追加されます。設定できる値は任意の項です。,第二引数はソートされていることが前提となる述語で、拡張ライブラリ組込述語「in /xfx」の下層述語(AZ-Prolog本体側に組み込まれた述語の意。単に領域制約を設定するだけで、ソートは上層側の責任において行う)となります。,<例>,| ?-put_clp_area(X,[1,2,5..7]),get_clp_area(X,L).,X = X,,L = [1,2,5..7],yes,| ?-put_clp_area(X,[a,b,d,1,2,5..7]),put_clp_area(X,[b,2..6]),get_clp_area(X,L).,no,% アトムは数値より大きいので、つぎのようにソートして領域設定する。,| ?-put_clp_area(X,[1,2,5..7,a,b,d]),put_clp_area(X,[2..6,b]),get_clp_area(X,L).,X = _43,,L = [2,5,6,b],yes,(5)決定性述語: rm_clp_area/2 ,既に値領域が設定されている変数から指定領域を取り除きます。,拡張ライブラリ組込述語「notin /xfx」の下層述語です。,<例>,| ?-put_clp_area(X,[1..9]),rm_clp_area(X,4..7),get_clp_area(X,L). X = X,L = [1..3,8,9]yes,(6)決定性述語: get_clp_area/2 ,変数に値領域が設定されている場合、その設定領域を取得します。呼び出し時点で既に変数の値が決定している(既に変数ではない)場合は失敗します。,拡張ライブラリ組込述語「indomain/1」などの下層述語です。,<例>,| ?-X in 0..9,get_clp_area(X,L).,X = X,,L = [0..9],yes,(7)決定性述語: clp_intersection/3 ,「put_clp_area/2」の補助述語(汎用)で、2集合の共通部分を取得します。,<例>,| ?-clp_intersection([1,3..6,9..12],[2..11],L).,L = [3..6,9..11],yes,(8)決定性述語: clp_is_member/2 ,「put_clp_area/2」「in /xfx」の補助述語で第一引数が第二引数のリストに含まれる場合成功します。,<例>,| ?- clp_is_member(a,[1..9,b,c(z)]).,no,| ?- clp_is_member(a,[1..9,a,c(z)]).,yes,| ?- clp_is_member(7,[1..9,a,c(z)]).,yes,(9)決定性述語: system_get_min_max_int/2 ,処理系で扱う整数の下限と上限を取得します。,<例>,| ?- system_get_min_max_int(MinInt,MaxInt).,MinInt = -9223372036854775808,,MaxInt = 9223372036854775807,yes,(10)決定性述語: s_constraints_mode/2 ,A1,A2ともonまたはoff,A1 現在の制約マクロ展開モード,A2 設定する制約マクロ展開モード,モードがonのとき、読み込みにおいて制約マクロ記述を展開して(変数に制約を付与して)読込みます。,読み込んだ項に含まれる制約記述をすべて実行するので、そのままアサートされることは前提としません。off のときは入力どおりの内容で読込みます。,<例>,?- s_constraints_mode(_,on).,(1) TopLevelでの入力,| ?- X={a:A#(A=B),b:B}.,X = {a:_2,b:_4} % _2は _2=_4に制約されている,yes,| ?- X={a:A#(A=B),b:B},X={a:aa}.,X = {a:aa,b:aa},yes,(2) Read系,read/1,read/2,d_read/2,d_read/3,| ?- read(X),X=a(1,C).,|: a(A#(B is A+2) , B). ,X = a(1,3),C = 3,yes,(3) 内部でReadを利用している述語,term_atom/2(atom->termのみ),term_string/2(string->termのみ),redis_command_to_term/4,<term_atomの例>,| ?- term_atom(T,'a(A#(B is A+2) , B)'),T=a(3,Y).,T = a(3,5),Y = 5,yes,<Redis を使う例>,:- dlib_require(redis).,test_fs_macro(V):-,redis_connect('127.0.0.1',6379,3000,CON), % Redisコネクト,redis_command(CON,[set,'mykey1',{a:X#[1,2,3],b:Y#(X=Y) }],_,_),  % 辞書セット,s_constraints_mode(OnOff,on), % マクロ展開モードに切替,errorset(redis_command_to_term(CON,'get mykey1',_,V),Err),!, % 辞書読み込み,s_constraints_mode(_,OnOff), % マクロ展開モードを戻す,redis_free_context(CON), % Redisコネクションを切る,Err=succ.,| ?- X= {b:2},test_fs_macro(X).,X = {b:2,a:2},yes,次の述語においては従来どおりの動作である。,consult/1,reconsult/1,e_consult/0,e_reconsult/0,ファイルに制約マクロが記述されていて、それを活かしたい場合は後述する macro_consult/1を使用する。,(11)決定性述語: is_clp_macro_exist/2 ,A1,A2ともonまたはoff,A1 直前のRead(TopLevel含む)にマクロ制約変数が含まれていたとき、自動でonとなります。,A2 on/offを再設定します。,s_constraints_modeの如何に関わらずフラグが自動セットされます。,<例>,| ?-s_constraints_mode(F,F).,F = off,yes,| ?-read(X),is_clp_macro_exist(F,F).,|: a(A#(A=B),B). ,X = a(A_31#(A_31=B_33),B_33),,F = on,yes,| ?-read(X),is_clp_macro_exist(F,F).,|: a(A,B).,X = a(A_25,B_27),,F = off,yes,| ?-s_constraints_mode(_,on).,_.2 = off,yes,| ?-read(X),is_clp_macro_exist(F,F).,|: a(A#(A=B),B).,X = a(_35,B_33),,F = on,yes,(12)決定性述語: macro_consult/1 ,コンパイル組み込み述語:ソース $(AZPROLOG)/system/pl/macro_consult.pl,マクロ制約記述を展開してコンサルトします。,head 部に含まれているマクロはneck部に、Goal部に含まれているマクロはそのGoal直前に,freeze/2,put_clp_area/2として変換挿入されます。,<例>,‹file›,a({が格:X#eat(X,Y),を格:Y}).,eat(猫,ネズミ).,eat(ネズミ,チーズ).,| ?- macro_consult(file).,yes,| ?- X={が格:ネズミ},a(X).,X = {が格:ネズミ,を格:チーズ},yes,| ?- listing(a). % Macro展開,a({が格:X,を格:Y},A):- freeze(X,eat(X,Y)).,・ファイルコンサルト時にエラーが発生した場合、その場所を知るにはechoモードをonにしてからコンサルトするとわかりやすい。,| ?-echo(_,on),macro_consult(file).,・AZEditバッファからのマクロ展開コンサルト方法,| ?- e_jump(0),e_markend,macro_consult(edit).,・コンソール直接入力のマクロ展開コンサルト方法,| ?-macro_consult(user).,|: a(X#(X=Y),Y).,終了は Windows コントロールZ、Linux コントロールD,・複数の変数が相互に関係する制約マクロの記述例,<ファイル test.pl>,a(A#test(A,B,C,D, Z), B#test(A,B,C,D, Z) ,C#test(A,B,C,D, Z) ,D#test(A,B,C,D, Z), Z)., test(A,B,C,D, Z):- nonvar(A),nonvar(B),nonvar(C),nonvar(D),Z is A+B+C+D., test(_,_,_,_, _).,<実行>, ?- macro_consult('test.pl')., yes, ?- a(1,2,3,4,Ans)., Ans = 10, yes, ?- a(A,B,C,D,Ans),D=1,A=2,C=3,B=4., Ans = 10, yes,B.拡張ライブラリ組込述語,拡張ライブラリの読込み(dlib_require/1)で組み込まれる述語です。,| ?- dlib_require(clp).,system/ext/clp/clp.plにprologソースで提供していますので、コンサルトでも使うことができ、ユーザーが手を加えることも可能です。ソースには下記以外にも定義述語がありますのでご参照ください。,(1)決定性述語: in /xfx ,変数が取り得る値領域の制約(値のリスト)を与えます。,詳細は述語リファレンスをご参照ください。,(2)決定性述語: notin /xfx ,変数が取り得ない値領域(値のリスト)の制約を与えます。,詳細は述語リファレンスをご参照ください。,(3)決定性述語: alldifferent/1,引数リストに含まれる変数はすべて異なる値を持つという制約を与えます。,詳細は述語リファレンスをご参照ください。,(4)非決定性述語: indomain/1 ,制約変数の取りうる値を非決定的にユニファイします。,詳細は述語リファレンスをご参照ください。,(5)非決定性述語: labeling/1 ,与えられた制約に基づいて探索を行います。,詳細は述語リファレンスをご参照ください。,(6)決定性述語: #= /xfx,演算子の左右の数(式)の計算結果が等しいという制約を与えます。,(7)決定性述語: #¥= /xfx,演算子の左右の数(式)の計算結果が等しくないという制約を与えます。,(8)決定性述語: #< /xfx,演算子の右の数(式)の計算結果が左の数(式)の計算結果より大きいという制約を与えます。,(9)決定性述語: #> /xfx,演算子の左の数(式)の計算結果が右の数(式)の計算結果より大きいという制約を与えます。,(10)決定性述語: #=< /xfx,演算子の右の数(式)の計算結果が左の数(式)の計算結果より大きいか等しいという制約を与えます。,(11)決定性述語: #>= /xfx,演算子の左の数(式)の計算結果が右の数(式)の計算結果より大きいか等しいという制約を与えます。"}); htmllist.push({"file":"manuals/manual_clp.html#clp_3","title":"9-3-3.プログラミング例題","text":"9-3-3.プログラミング例題,例題1.数独,数独とは正方形の枠内の空いているマスに数字を埋めるパズルで、数字は各列(縦)/各行(横)/各ブロック内のいずれにも同じ数字が複数含まれないように並べるのがルールです。,ここでは、説明を簡単にするため、4X4マス(2X2の4ブロック)からなる数独の解法を説明します。,使われる制約組込述語は「in /xfx」「alldifferent/1」「labeling/1」の3述語です。,ヒントとして、4つのマスの値が示されているとします。,[ _, 1, _, _,,_, _, 2, _,,3, _, _, _,,_, _, _, 4],なお、「sample/clp/sudoku.pl」には、通常の9x9は勿論、NxNマス(Nは正の整数の平方根を持つ数字)の解法に一般化した例題がありますので、合わせてご確認ください。,:- dlib_require(clp). % 拡張ライブラリをロードします,go:- % 4x4の変数領域を作ります。マス目を左上から順に異なる変数で埋めます,Vars = [X1, X2, X3, X4,,X5, X6, X7, X8,,X9, X10, X11,X12,,X13,X14, X15,X16],,% ヒントとユニフィケーションして確定値を埋めます,X2=1,X7=2,X9=3,X16=4,,% 各変数は1から4までの数値が入るという制約を与えます,Vars in 1..4 ,,% 各行に含まれる変数はすべて異なる値を持つという制約を与えます,alldifferent([X1, X2, X3, X4]),,alldifferent([X5, X6, X7, X8]),,alldifferent([X9, X10, X11,X12]),,alldifferent([X13,X14, X15,X16]),,% 各列に含まれる変数はすべて異なる値を持つという制約を与えます,alldifferent([X1,X5,X9,X13]),,alldifferent([X2,X6,X10,X14]),,alldifferent([X3,X7,X11,X15]),,alldifferent([X4,X8,X12,X16]),,% 各ブロックに含まれる変数はすべて異なる値を持つという制約を与えます,alldifferent([X1,X2,X5,X6]),,alldifferent([X3,X4,X7,X8]),,alldifferent([X9,X10,X13,X14]),,alldifferent([X11,X12,X15,X16]),,% 以上の制約で探索を行います,labeling(Vars),,% 結果を表示します。,write([[X1,X2], [X3,X4]]),nl,,write([[X5,X6], [X7,X8]]),nl,nl,,write([[X9,X10], [X11,X12]]),nl,,write([[X13,X14],[X15,X16]]),nl.,| ?- go.,[2,1] [4,3],[4,3] [2,1],[3,4] [1,2],[1,2] [3,4],yes,※「数独(スウドク)」はニコリの登録商標(第3327502号など)で、日本では「ナンバープレース」と呼ばれることも多い。日本以外の国ではSudokuという呼称が一般的。,例題2.魔方陣,魔方陣とは正方形に並んだマスに、各列(縦)/各行(横)/両対角線のいずれの合計も同じになるように数字が並んだものを言います。,ここでは3X3魔方陣の解法を説明します。,使われる制約組込述語は「in /xfx」「alldifferent/1」「labeling/1」「#= /xfx」の4述語です。,なお、「sample/clp/magic.pl」では、NxNマスの魔方陣が解けるようになっています。,比較のため、このファイルには通常のPrologコードの生成検査法によるプログラムも収められています。,生成検査法では、4X4魔方陣においては16の階乗=20兆とおりの組み合わせを試すことになり、最初の解を得るのでさえ相当の時間を要しますが、制約論理プログラミングでは、数分のうちに全解を求めることができます。,ただし、N=6以上では第一解でさえ相当の時間を要します。,:- dlib_require(clp). % 拡張ライブラリをロードします,go:-,Vars = [X1,X2,X3, % 変数領域を設定します,X4,X5,X6,,X7,X8,X9],,Vars in 1..9, % 各変数は1から9までの数値が入るという制約を与えます,alldifferent(Vars), % 各変数はすべて異なる値をとるという制約を与えます,15 #= X1+X2+X3, % 第1行のマスの合計値が15になるという制約を与えます,15 #= X4+X5+X6, % 第2行のマスの合計値が15になるという制約を与えます,15 #= X7+X8+X9, % 第3行のマスの合計値が15になるという制約を与えます,15 #= X1+X4+X7, % 第1列のマスの合計値が15になるという制約を与えます,15 #= X2+X5+X8, % 第2列のマスの合計値が15になるという制約を与えます,15 #= X3+X6+X9, % 第3列のマスの合計値が15になるという制約を与えます,15 #= X1+X5+X9, % 左上右下対角線のマスの合計値が15になるという制約を与えます,15 #= X3+X5+X7, % 右上左下対角線のマスの合計値が15になるという制約を与えます,labeling(Vars), % 以上の制約で探索を行います,write([X1,X2,X3]),nl, % 結果を表示します。,write([X4,X5,X6]),nl,,write([X7,X8,X9]),nl.,| ?-go.,[2,7,6],[9,5,1],[4,3,8],yes,例題3.覆面算,覆面算とは0から9までの数字がそれぞれユニークな別の記号に置き換えられた計算式から、各記号の意味(数字)を割り出すパズルです。元の数字列の最上位に位置する記号は0ではないものとします。,ここでは覆面算SEND+MORE=MONEYの解法を説明します。,使われる制約組込述語は「in /xfx」「alldifferent/1」「labeling/1」「#= /xfx」「#¥= /xfx」の5述語です。,「sample/clp/sendmore.pl」にソースがあり、比較のため通常のPrologコードで生成検査法によるプログラムもこのファイルに収められています。,:- dlib_require(clp). % 拡張ライブラリをロードします,go:-,Vars = [S,E,N,D,M,O,R,Y], % 変数領域を設定します,Vars in 0..9, % 各変数は0から9までの数値が入るという制約を与えます,alldifferent(Vars), % 各変数はすべて異なる値をとるという制約を与えます,S #¥= 0, % S は0ではないという制約を与えます,M #¥= 0, % M は0ではないという制約を与えます,S*1000+E*100+N*10+D % SEND+MORE=MONEY であるという制約を与えます,+M*1000+O*100+R*10+E,#= M*10000+O*1000+N*100+E*10+Y,,labeling(Vars), % 以上の制約で探索を行います,write(Vars),nl. % 結果を表示します。,| ?-go.,[9,5,6,7,1,0,8,2],yes,例題4.つるかめ算,つるかめ算は、つるとかめのように異なる足の数を持つ動物の個体数(匹数,頭数)の合計と足の数の合計が分かっているときに、それぞれの個体数を求める算術です。,ここでは、プログラムのトレースを通じて変数の制約が絞られていく過程を見てみましょう。,|?-listing.,turukame(Turu,Kame,Foot,Head) :-,Turu in 0..Head,,Kame in 0..Head,,Foot#=Turu*2+Kame*4,,Head#=Turu+Kame.,yes,|?-trace.,yes,||?-turukame(X,Y,14,5).,[1] 0 Try : turukame(X_7,Y_9,14,5) ?,Match : turukame(X_7,Y_9,14,5) :-,X_7 in 0..5,,Y_9 in 0..5,,14#=X_7*2+Y_9*4,,5#=X_7+Y_9.,[2] 1 Try : X_7 in 0..5 ? i % Iコマンド,Foot = 14 % 定義節の変数:Foot は 14に束縛されています,Head = 5 % 定義節の変数:Head は 5に束縛されています,[2] 1 Try : X_7 in 0..5 ?,‹‹ BUILTIN CALL ››,[2] 1 Succ : _30 in 0..5,[2] 1 Try : Y_9 in 0..5 ? i % Iコマンド,Turu = _30 { [0..5]::true } % 定義節の変数:Turu は 0..5 に制約されています,Foot = 14,Head = 5,[2] 1 Try : Y_9 in 0..5 ?,‹‹ BUILTIN CALL ››,[2] 1 Succ : _46 in 0..5,[2] 1 Try : 14#=_30*2+_46*4 ? i % Iコマンド,Turu = _30 { [0..5]::true },Kame = _46 { [0..5]::true },Foot = 14,Head = 5,[2] 1 Try : 14#=_30*2+_46*4 ?,‹‹ BUILTIN CALL ››,[2] 1 Succ : 14#=_30*2+_46*4,[2] 1 Try : 5#=_30+_46 ? i,Turu = _30 { [1,3,5]::$clp_area_propagation(7,[1,2],[_30,_46]),! } % 制約が狭まりました,Kame = _46 { [1..3]::$clp_area_propagation(7,[1,2],[_30,_46]),! } % 制約が狭まりました,Foot = 14,Head = 5,[2] 1 Try : 5#=_30+_46 ?,‹‹ BUILTIN CALL ››,[2] 1 Succ : 5#=3+2 % この制約で値が求まりました,‹‹ LAST CALL ››,[1] 0 Succ : turukame(3,2,14,5),X = 3,,Y = 2,yes"}); htmllist.push({"file":"manuals/manual_parallelprocessing.html#parallel","title":"9-4-1.概要","text":"9-4-1.概要,AZ-Prologの並列処理支援の仕組みは、GHCのような言語に内包された機能ではなく、Prologのシンタックスそのままで、プログラム上で明示的に複数のプロセスに分散して粒度が粗い並列処理を行うものです。,プログラマは処理の切り分けと並列化をプログラミングしなければなりません。MPI(Message Passing Interface )と同様なものであるとお考えください。,AZ-PrologはVersion3(1995年リリース)の頃から、子プロセスを立ち上げプロセス間通信を行う述語( s_child/5 )が用意されていました。この述語は、OSコマンド(DIR等)をコマンドプロセッサ(cmd.exe等)に送信して受け取った結果をPrologプログラム側で処理を行ったり、並列に多数のネットワークノードに「Telnet」「Snmp」で接続して同時刻での情報を得る等の目的で使われてきました。,CPUがシングルコアだった頃は、複数の処理を並列に行って結果を結合しても、上記のような目的以外ではかえって処理時間がかかってしまい、あまり意味をなさないものでした。,しかしながら、昨今のCPUはマルチ/メニー・コアの流れが加速されており、この資源を生かすことでコア数倍の高速化が図れるようになっています。,手軽に並列化するごく簡単な手段で高速に結果を得ることが可能となったのです。"}); htmllist.push({"file":"manuals/manual_parallelprocessing.html#parallel_2","title":"9-4-2.述語説明","text":"9-4-2.述語説明,以下の表は、次に説明するソース提供された並列処理用の述語とは別にAZ-Prolog本体に実装されている組込述語の一覧です。一部の述語は並列処理支援機構実装時の必要性から追加で組み込まれたものです。,従来からある組込述語, s_child/5 ,子プロセスを立ち上げる.,s_child(+実行形式プログラム,+[パラメータ並びリスト],-InStream,-OutStream,-ProcessID), s_kill/2 ,子プロセスを削除する.,s_kill(+ProcessID,0)., s_sleep/1,指定ミリ秒スリープする,追加組込述語, s_flush/0 ,標準出力バッファの強制フラッシュ。受信側プロセスで読み込めるようにする。, s_can_read/1 ,OutStreamから読み込み可能な場合(子プロセス側で標準出力に戻値出力)にのみ成功。, s_can_read/2 ,OutStreamから読み込み可能な場合に成功し、読み込み可能バイト数を返す。,(1)並列処理関連述語のPrologソース,並列処理関連の述語は以下のソースファイルで定義されています。,(これらはいずれもAZ-Prologインストールディレクトリ下の「¥system¥pl」にあります。),mlt_parent.pl 親プロセス側の並列処理用述語(子プロセスも孫プロセスを生成する場合には利用する),mlt_child.pl¥ 子プロセス側の並列処理用述語,提供インタプリタはほぼ次のようにコンパイルされていますので、子プロセス用Prologインタプリタとしてはprolog_c.exeを使うことができます。,C:¥>azpc -p setof.pl utility.pl mlt_child.pl mlt_parent.pl /i /dcurses /e prolog_c,C:¥>azpc -p setof.pl utility.pl mlt_parent.pl /i /e prolog,もちろん、mlt_child.pl mlt_parent.plの両方を含めた実行プログラムを代わりに作成しても構いません。,(2)並列処理用述語の説明,詳細は、「mlt_parent.pl mlt_child.pl」を読んでください。子プロセスへのゴールの与え方と結果の受け取り方で目的の違う処理が構築できます。,複数の子プロセスの生成, mlt_proc/2 ,指定個数のprolog_c子プロセスを起動する。,第1引数:,生成するProlog子プロセスの個数,第2引数:,生成プロセス情報のリスト(出力), ,1プロセス当たりの情報は以下の通り。,[子プロセスID,入力FP,出力FP,実行プログラム,起動パラメタリスト],例.,[1916,fp_f79090,fp_f79140,prolog_c,[-child]], mlt_proc/5 ,指定個数の実行プログラムプロセスを指定引数で起動する。,第1引数:,生成する子プロセスの個数,第2引数:,実行プログラム(prolog_cが前提),第3引数:,領域指定,第4引数:,その他の起動パラメタ(-p以下に続く。読込みプログラム等),*読込みプログラムはconsult/b_load/compile/assert/execの述語呼び出し形式の指定が可能です。,第5引数:,生成プロセス情報のリスト(出力),プロセス情報は mlt_proc/2 と同じ,子プロセスにゴールを与える, mlt_send/2 ,各プロセスに実行すべきゴール情報を送信する。,第1引数:,mlt_proc/[2または5]で生成されたプロセス情報リスト,第2引数:,各プロセスに実行させるゴール情報リスト, ,ゴール情報の与え方には以下の3方式がある。受取結果については[子プロセスから結果を受け取る]を参照。,(a) ゴール,ゴールを実行するだけで戻り値を要求しない場合に用いる。,?-mlt_proc(3,P),mlt_send(P,[true,true,true]).,(b) [ゴール,戻り値],ゴールが成功したとき返す戻り値を指定。,?-mlt_proc(2,P),mlt_send(P,[[put(4,L),L],[put(5,M),M]]).,(c){ゴール,戻り値},(b)と同じだが、戻したあと強制バックトラックされ、別解が取れる。,?-mlt_proc(2,P),mlt_send(P,[{put(4,L),L},{put(5,M),M}]).,各子プロセスが非決定的に複数解を返す場合に用い、結果の受け取りには mlt_scan_each/2 を呼ぶ。,子プロセスから結果を受け取る,下記の述語の引数は述語のアリティに応じて以下の通り。,第1引数:,mlt_proc/[2または5]で生成されたプロセス情報リスト(共通),第2引数:,ゴール実行の結果(出力)(アリティ2の場合),スキャンインターバル(ミリ秒)(入力)(アリティ3の場合),第3引数:,ゴール実行の結果(出力)(アリティ3の場合のみ),受け取る結果内容は mlt_send/2 に与えるゴールの方式に応じて、以下のいずれか(最速の結果のみの場合)、もしくはこれらから成るリスト(全ての結果を取得する場合)。,1)方式(a)の場合、および方式(b)(c)でエラー/failの場合,実行ステータス:「status(exe,Status)」という形式の項(Statusはsucc,failまたはエラー番号),2)方式(b)(c)で正常終了した場合,送信したゴールを実行した結果の指定戻り値,但し、 mlt_scan2/3 では「プロセスID=戻り値」となっている。ソースが提供されているので、必要に応じて修正は可能。, mlt_receive/2 ,を含む全ての結果を起動順に読み込む。, mlt_receive/3 ,を含む全ての結果を到着順に読み込む。, mlt_scan/3  ,を含む最速の結果のみを読み込む。, mlt_scan2/3  ,を除く最速の結果を読み込む。,すべてなら述語そのものが失敗する。, mlt_scan_each/2  ,を除く結果を早い順に受け取る。,バックトラックで次の結果を取れる。,子プロセスを強制終了する, mlt_kill/1 ,引数はmlt_proc/[2,5]で生成されたプロセス情報リスト"}); htmllist.push({"file":"manuals/manual_parallelprocessing.html#parallel_3","title":"9-4-3.プログラムの書き方","text":"9-4-3.プログラムの書き方,サンプルプログラム(%AZ-Prolog%¥sample¥parallel下)を解説しながら、並列処理関連の述語の使い方を説明します。,(1)データ並列,異なるデータに同一の処理を並列で施し、結果を結合します。,Nqueen,4クイーンの場合、リスト[1,2,3,4]を条件(既に置いた駒の効き筋上に新たな駒を置かない事)を満たすように並べ替えて全解を取得しますが、リストの最初の要素(最初の列に置く駒の行位置)をそれぞれ1,2,3,4に固定して、それ以外の要素の並べ替え(残り3列への駒の配置)を行うようにデータを振り分けた4プロセスに並列化可能です。,サンプルファイルqueen.plでは、例えば1つ目の駒が最初の列の1行目に置かれた状態で残りの駒を配置する場合の解は、述語put/3を用いて、,?-put([2,3,4],[1],Ans).,で得られます。従って、全ての解を求めるには、,?- ( put([2,3,4],[1],Ans); put([1,3,4],[2],Ans); put([1,2,4],[3],Ans); put([1,2,3],[4],Ans) ).,とすれば良いことになります(「?-」に続けて記号を書く事はできないので、この例のようにスペースを入れます)。,このOR部分(セミコロンで区切られた各部)を各プロセスに割り当てて並列に解くプログラムは次のようになります。,:-['queen.pl'].,queens:-,List = [1,2,3,4],,length(List,Ln),,bagof({put(Else,[F],Ans),Ans},select(List,F,Else),Pattern), % 一列目におくQueenの位置全とおりを生成,mlt_proc(Ln,prolog_c,'',compile('queen.pl'),Proc), % List長数のプロセスを生成,mlt_send(Proc,Pattern), % 各プロセスにパターンを割り振る,( mlt_scan_each(Proc,X),write(X),nl,fail; % 各プロセスから全結果を取得,mlt_kill(Proc) ). % プロセスを消去,4通りのput/3呼び出しパターンを生成するためにNqueensを解く時と同じ述語 select/3 を呼び出しているので、queen.plを最初にコンサルトしています。,サンプルプログラムには、同様にデータ並列化可能な例題として、素数生成(prime.pl)、ペントミノパズル(pentomino.pl)を用意しています。,以下にpentomino.plのメニューで逐次処理(メニューの2番)/並列処理(メニューの5番)のそれぞれを実行した場合に各CPUの使用率がどのようになっているかを参考までに示します。Windows版で実行した際に、タスクマネージャーから起動できるリソースモニターに表示されたグラフです。ページの都合によりレイアウトは変更してあります。並列実行の場合に処理の負荷分散がうまくなされている様子が分かります。,1)逐次処理の場合,  ,2)並列処理の場合,  ,(2)処理並列,互いに依存しない複数のサブゴールが並列で処理できれば、最長部分のみの処理時間で済みます。,逐次:,a(A,AA),b(B,BB),c(C,CC), d(AA,BB,CC,Ans),....,3秒 + 20秒 + 10秒 =33秒,逐次に処理すると合計で33秒かかる。並列:,┌─ a(A,AA) ─┐,─┼─ b(B,BB) ┼─ d(AA,BB,CC,Ans),,└─ c(C,CC) ─┘,並列だと20秒で処理できる。,計算コストが大きいことで知られるアッカーマン関数(3,10)の結果とフィボナッチ数列(35)の結果を加算することを考えてみましょう。,サンプルファイルfibo_ack.plに両数値を計算するための述語fibo/2およびack/3は用意されています。いずれも定義通りです。,逐次計算するなら、,seq_ack_fibo:- fibo(35,X),ack(3,10,Y),Ans is X+Y,write(ans=Ans).,と書くところですが、このfibo(35,X)とack(3,10,Y)を並列で計算する場合のプログラムは次のように書けます。,ack_fibo:- mlt_proc(2,prolog_c,'',compile('fibo_ack.pl'),Proc), % fibo.pl を起動時に読込むプロセスを生成 mlt_send(Proc,[[fibo(35,X),X],[ack(3,10,Y),Y]]), % 各プロセスに異なる[ゴール,返し値]を送信 mlt_receive(Proc,[X,Y]), % 出力ストリームから計算結果を受け取る Ans is X+Y, write(ans=Ans), % 両方の計算結果を加算する mlt_kill(Proc).,(3)アルゴリズム並列,適用するアルゴリズムによって、データの散らばり方に依存して格段の処理速度の違いが生じる場合があります。,このような時、全てのアルゴリズムを同一データに対して並列で処理させ、最速結果のみを採用することが可能です。例として4種類のアルゴリズムで同一データのソートを考えてみましょう。これらのソート用述語はサンプルプログラムsort_pack.plで定義されていると仮定しています。次のようにすれば、最初に解が得られたアルゴリズムのタイムコストで済みます。,sort_pack.plは現在は提供されていません。http://nojiriko.asia/などにも色々なソートアルゴリズムが紹介されているので、課題としておきます。ソート対象を十分に大きくすると、アルゴリズムの効率の違いがよりはっきりします。,mlt_sort(L,Ans):-mlt_proc(4,prolog_c, '',compile('sort_pack.pl'),Proc),mlt_send(Proc,[[qsort(L,A),A],[msort(L,A),A],[bsort(L,A),A],[binsort(L,A),A]]),mlt_scan2(Proc,0,Ans), % fail,errorでない最速で解を返したものを採用mlt_kill(Proc). % 計算中のものも含め子プロセスを削除してしまう"}); htmllist.push({"file":"manuals/manual_cgi.html#cgi","title":"9-5-1.概要","text":"9-5-1.概要,Prologで書かれたCGIプログラムを翻訳・実行して動的なWEBページを実現するための枠組みを提供します。,本マニュアルでは、WEBサーバとしてApacheを前提として説明しています。,CGI用Prologインタプリタはソースファイル(prologcgi.pl)も提供されていますので、参考にしてください。"}); htmllist.push({"file":"manuals/manual_cgi.html#cgi_2","title":"9-5-2.PrologによるCGIの利用方法","text":"9-5-2.PrologによるCGIの利用方法,(1)apache のインストールとデモプログラム、環境の設定,最終的にサーバーでプログラムを公開するにしても、デバッグ・開発用にクライアントマシンにもApacheのインストールをしておくことをお勧めします。,Apacheは下記のいずれかの方法で入手・インストールできます。必要に応じて関連WEBサイト、書籍などをお読みください。,Apacheの入手・インストール方法(本マニュアル改訂時2014年6月現在),1),Apache Software Foundation(URL:http://www.apache.jp/)からソースを入手してインストール,2),同サイトからバイナリを入手してインストール(Windows32bitのみ),3),サードパーティのサイトからWindows64bit版バイナリを入手してインストール,http://www.apachelounge.com/download/,4),UbuntuソフトウェアセンターからApacheパッケージを入手してインストール,$ sudo apt-get install apache2.2-common,$ sudo apt-get install apache2-mpm-prefork,※この場合、コンフィグレーションが他と大きく異なります。,5),Mac OS X でApacheパッケージを入手してインストール,$ sudo port install apache2,AZ-Prologのトップサイト(http://www.az-prolog.com/)の「ラーニング(Learning)」のプルダウンメニューにある「CGIサンプルプログラム」で見れるのと同様のデモが、AZ-Prologのインストールディレクトリ下の「sample¥cgi_demo」に入っています。,このデモをローカルマシンのApache上にインストールして動かすには以下の手順に従います。環境によって一部動かないもの、手を加える必要のあるものがありますが、これについては手順表の下の注意書きをご覧ください。,CGIサンプルデモを見るための手順,1),AZ-Prologのサンプルディレクトリ(sample¥cgi_demo¥cgi-bin)にある全ファイルをApacheのcgi-binへコピー,2),AZ-Prologのサンプルディレクトリ(sample¥cgi_demo¥htdocs)にある全ファイル・ディレクトリをApacheのドキュメントルートへコピー,3),ODBCのデモ(Windows版のみ)には、あらかじめ設定が必要です。,AZ-Prologの拡張機能ODBCの提供サンプルソース(sample¥odbc¥odbc_test.pl)に書かれている方法でODBCのDNS(同名、同ログイン名/パスワード)を設定し、同じファイルをインタプリタに読み込んでテーブル及びデータを生成しておいてください。ODBCについては9-9.ODBCを参照してください。,4),日本語形態素解析器:MeCab、及び日本語係り受け解析器:CaboCha(Windows版32bitのみ)のデモのためには、これらのインストールが必要です。詳細は9-5.Mecab/Cabochaを参照してください。,5),Windows版Apache(32,64bitとも)では、httpd.confの任意の場所に次の設定を追記してください。,PassEnv AZPROLOG,Windows版Apache64bitでは、,5-1) コントロールパネルのシステム環境変数の設定で「MECABのインストールフォルダ¥etc¥mecabrc」を設定します。,     [変数名] MECABRC,     [値(例)] C:¥Program Files (x86)¥MeCab¥etc¥mecabrc,5-2) httpd.confの任意の場所に次の設定を追記してください。,PassEnv MECABRC,httpd.confを書き換え後、コントロールパネル->管理ツール->サービスでApacheを再起動します。,6),上記が終了しましたら、ブラウザを開き、アドレス欄に次の入力でデモを開始することができます(Apacheが動作していなければならないのは勿論です)。,http://localhost/az_index.html,注意:,1),Linux版またはMac OS X版で「ソースを表示する」を選ぶと、エラーになります。,system/pl/puttext.plをコンパイルしてcgi-binの下に置いてください。コンパイル方法は同ファイルに書かれています。,2),Nクイーンのバイトコード版やフルコンパイル版が正しく動かない場合は、cgi-binの下にあるqueen.cgiをコンパイルしてください。コンパイル方法は同ファイルに書かれています。,3),鬼車、MeCab、ODBCなどで正しく表示されない場合は、拡張機能の対応するマニュアルも参照してください。"}); htmllist.push({"file":"manuals/manual_cgi.html#cgi_3","title":"9-5-3.PrologによるCGIの書き方","text":"9-5-3.PrologによるCGIの書き方,以下、PrologでCGIプログラムを書く場合のポイントについて順に説明します。,(1) CGI用Prologインタプリタの指定,Prologで記述するCGIのソースコードの一行目にCGI用Prologインタプリタを記述します。これにより、それに続くPrologのソースコードが解釈実行され、CGIプログラムとして機能します。,インタプリタ名のみで指定する場合と、フルパスで指定する場合とがあります。開発環境から本番環境へ移行する際、前者はそれぞれの環境でprologcgiのPATHが通っていればそのまま動きますが、さもなければ見つかりません。後者はPATHが通っていなくても実行が可能ですが、両環境でAZ-Prologのインストールディレクトリが異なる場合には動きません。それぞれ一長一短があります。,<例:インタプリタ名のみ指定する場合>,#! prologcgi,<例:フルパスで指定する場合(Windows 64bit版の例)>,#! C:¥Program Files¥AZ-Prolog.8xx¥bin¥prologcgi,<例:フルパスで指定する場合(Ubuntu版標準インストールの例)>,#! /usr/local/bin/prologcgi,<例:フルパスで指定する場合(Mac版標準インストールの例)>,#! /Applications/azprolog.app/Contents/az_home/bin/prologcgi,(2) トップレベル述語の指定,PrologCGIの起動直後に呼び出される処理を指定するには、トップレベルの述語(top_call/0)をソースコードに必ず記述します。,top_call:- 処理.,処理の部分に記述するのは、CGIの起動を要求(HTTPリクエスト)したブラウザ画面から送られたパラメタを取得し、それに基づいて処理を行って、次に遷移すべき動的なページを構成して標準出力(つまりブラウザ)に返す(HTTPレスポンス)と言う一連の流れのコードです。これらを記述するための各種組込述語が提供されています(「(6)CGI用拡張組込述語」を参照)。,(3) ページコンテンツの出力,HTTPレスポンスの本体をHTMLの構文規則に沿って記述し出力を行いますが、その前にHTTPレスポンスヘッダの一部としてコンテンツの種類や文字コードを表す行(下記はその一例)を出力します。ステータスコードやその他のヘッダ情報はWEBサーバが付加してくれます。,Content-Type: text/html; charset=utf-8,AZ-PrologのCGIインターフェースでは、HTML中に変数の値や処理の結果(述語呼び出しの結果出力)を動的に埋め込むことができます。HTMLの詳細については他の説明書などをお調べください。ブラウザでの改行表示は,だけで十分ですが、出力したHTMLをソース表示した場合などの見やすさを考慮し、「nl」を補っておくといいでしょう。,(4) バイトコードコンパイルによる高速化,Prologで記述されたCGIプログラムをバイトコードコンパイルすることにより、インタプリタコード(Prologソースコードをインタプリタに読み込んだコード)を解釈実行する場合と比較して、実行スピードを4倍程度速くすることが可能です。,バイトコードコンパイルはAZ-Prologコンパイラ(azpc)を使って容易に行えます。,<例:queens.cgiをバイトコードコンパイルする場合>,C:¥>azpc -p queens.cgi /byte,C:¥>ren queens.b queenb.cgi,バイトコードコンパイルでは、拡張子「.b」の付いたファイルが生成されますが、バイトコードに変換したCGIプログラムであることを明確にするために、上の例では名前を変更しています。,(5) フルコンパイルで更に高速化、多機能化,prologで書かれたCGIプログラムをフルコンパイルすると、10倍程度実行スピードが上がります。フルコンパイルするには、AZ-Prologのインストールディレクトリ下、system¥plにあるprologcgi.pl、utility.plを同時にコンパイルリンクします。コンパイルオプションに、「/no」と「/dcurses」を指定してください。以下の例では分かり易くするためにパスは省略しています。,<例:queens.cgiをフルコンパイルする場合>,C:¥>azpc -p queens.cgi utility.pl prologcgi.pl /fast /e queens /no /dcurses,フルコンパイルでは、本パッケージで提供される拡張機能(鬼車、めかぶ、かぼちゃ、Redis他)をリンクすることで、サーバサイドのWEBアプリケーションとしての多機能化を実現するすることができます。拡張機能を利用したり複数モジュール間の連携にはpublic宣言、extern宣言等の各種宣言が必要になります。これについては「7.コンパイラ」の章を参照してください。,(6) CGI用拡張組込述語,PrologでCGIプログラムを記述する際に利用できる拡張組込述語について解説します。,get_param/2,CGI呼び出しの際のパラメータを取得する。指定パラメータと一致するものがないときは失敗する。HTTPリクエストがGETメソッドの場合もPOSTメソッドの場合も同列に扱える。,第1引数:,パラメータ名,呼び出し元がHTMLの場合は、パラメータ名はsubmitされたformのinputタグのname属性の値に相当する。,第2引数:,パラメータの値(出力),ファイル送信の場合は{ファイル名、受信データタイプ、ファイル内容}の書式となる。,下記のようなformからファイル(仮にfile.dat、中身が"aaa")が送信された場合は、,パラメータ名:user_file,パラメータ値:{file.dat, application/x-ns-proxy-autoconfig, aaa},のようになる。,‹form enctype='multipart/Form-data' action='/cgi-bin/xxxx.cgi' method='POST'>‹input type='file' name='user_file'>‹input type='submit' value='Upload'>‹/form>,[ html_call/1 ],標準出力(ブラウザ)にヘッダ、HTMLタグを出力する。,第1引数:,出力内容のリスト,リストの要素に応じて以下のように処理される。,・要素が文字列なら1文字ずつ順に出力される。,・要素が変数なら値が出力される。,・要素が組込述call/1の呼び出し形式なら、引数のゴールが実行される。,(ゴールの出力内容が埋め込まれる),ヘッダとHTML開始タグの間には空行が必要になる(下記の例)。,html_call([,"Content-Type: text/html; charset=utf-8,<html><head/><body>,......  ,[html_tmplate/1],テンプレート機能を利用して標準出力(ブラウザ)にヘッダ、HTMLタグを出力する。変数名と値の対応情報は予め単位節「tmp_name(変数名,値).」の形で定義する。html_tmplate/2の下位述語。,第1引数:,テンプレートファイル名(アトム),テンプレートファイル中で使用できる置き換え用タグは以下の2つ。,1)書式:,変数名の指す変数が値を持っていれば値に置き換える。,2)書式:,...条件出力部分...,変数名の指す変数が値を持っていれば条件出力部分を出力する。,条件出力部分に1)のタグを入れ子にすることも可能。,tmp_mane/2を単位節でなく以下の様な述語として記述すれば、データベースから取得した値での置き換えも可能になる。,tmp_name(VarName,Value):-,get_key(ID),select_each([Value],tmp_get,[ID,VarName]),!.,[html_tmplate/2],テンプレート機能を利用して標準出力(ブラウザ)にヘッダ、HTMLタグを出力する。変数名と値の対応情報は引数で与える。,第1引数:,テンプレートファイル名(アトム),第2引数:,1)データファイル名(アトム)、または2)リスト,1)データファイルの場合:単位節「tmp_name(変数名,値).」が定義されたファイルをコンサルトする。,2)リストの場合:[変数名1=値1,変数名2=値2.....])の書式で与える。,単位節「tmp_name(変数名,値).」に焼き直されアサートされる。,単位節定義後はhtml_tmplate/1を呼び出す。,set_exit_timer/1,Prologプロセスを強制終了する経過時間を設定する。,CGIに限らず、バグや誤入力でプロセスが終了せずサーバー負荷が高まるのを防ぐ。,第1引数:,経過時間(整数値。単位:ミリセカンド),| ?-set_exit_timer(+整数).,(7) CGI利用時にシステムによって生成されるインタプリタコード,CGIプログラムから以下の情報が参照できます。,param_assoclist/1,CGI呼び出し時の全パラメータ(名前と値)のリストを保持する単位節。チェックリストのように同一のname属性を持つInputタグが複数ある場合でも、このリストから全てを取得できる(get_param/2では名前の一致する先頭要素の値のみ)。,| ?-param_assoc_list(-リスト).リスト=[タグ1、値1、タグ2、値2、タグ3、値4 ......],my_cgi_name/1,CGIプログラムのファイル名を保持する単位節。,| ?-my_cgi_name(?アトム).,(8) CGIプログラムのコマンドラインでの動作確認方法,パラメータ渡しのCGI呼出しは次のようにします。ブラウザに送られるHTML出力がコンソールに表示されます。,c:¥>prologcgi queens.cgi?”num=8&disp=true”"}); htmllist.push({"file":"manuals/manual_oniguruma.html#oniguruma","title":"9-6-1.概要","text":"9-6-1.概要,「鬼車」は小迫清美氏の開発による正規表現パッケージです。,最新のパッケージは次のURLからダウンロードすることができます。,https://github.com/kkos/oniguruma,※鬼車最新パッケージは、AZ-Prolog Ver9.6.2ではサポートされておりません。, AZ-Prologで鬼車をご利用される場合は、鬼車Ver5.9.6をダウンロードしてください。"}); htmllist.push({"file":"manuals/manual_oniguruma.html#oniguruma_2","title":"9-6-2.ライブラリのインストール","text":"9-6-2.ライブラリのインストール,Windows,パッケージにはコンパイル済のDLLライブラリが付属していますが、最新版は前記のURLからダウンロードし、Readmeに従ってコンパイルしてください。※鬼車Ver5.9.6をご利用下さい。,LinuxまたはMac,・前記URLからonigurumaパッケージをダウンロードします。,・解凍、Makeしてインストールします。,$ tar xvf onig-5.9.6.tar.gz,$ cd onig-5.9.6,$ ./configure,$ make,$ sudo make install,$ sudo ldconfig"}); htmllist.push({"file":"manuals/manual_oniguruma.html#oniguruma_3","title":"9-6-3.動作確認","text":"9-6-3.動作確認,AZ-Prologに付属している動作確認用のプログラムを読み込んで実行します。,Windows,>cd  %AZProlog%¥sample¥ext,>prolog -s oniguruma.pl,| ?- test.,LinuxまたはMac,$ cd ${AZProlog}/share/azprolog/sample/ext,$ prolog -s oniguruma.pl,| ?- test."}); htmllist.push({"file":"manuals/manual_oniguruma.html#oniguruma_4","title":"9-6-4.使用方法","text":"9-6-4.使用方法,0.Onigurumaライブラリをロードする,:- dlib_require(oniguruma).,1.正規表現オブジェクトを作成する,onig_pattern_compile(+PATTERN, -REGEX),PATTERN,正規表現パターン (アトム/文字列),REGEX,作成された正規表現オブジェクト,不正なパターンを指定すると失敗する。,<例>onig_pattern_compile('^[a-z]+', REGEX).,※正規表現パターンの文法については、以下を参照。,www.geocities.jp/kosako3/oniguruma/doc/RE.ja.txt,これと同じファイルが、インストールしたときの.../oniguruma/doc/RE.jaファイルとして存在するので、これを参照しても良いが、EUC-JPで書かれている。,2.使用しなくなった正規表現オブジェクトを開放する,onig_pattern_free(+REGEX),たくさん正規表現を使用するのでなければ、実行しなくてもよいかもしれない。,3.不正な正規表現パターンのエラー情報取得,onig_pattern_error_info(+PATTERN, -ERR),PATTERN,正規表現パターン (アトム/文字列),ERR,エラー情報のアトム,<例>onig_pattern_error_info('(', ERR).,==> ERR = 'end pattern with unmatched parenthesis',4.検索対象文字列オブジェクトを作成する,onig_make_target_string(+STRING, -TARGET_STRING),STRING,AZ-Prologの文字列(リスト)/アトム,TARGET_STRING,正規表現ライブラリで対象とする文字列オブジェクト,このライブラリはPrologの文字列を直接検索できないので、この述語によって変換したものを作成する必要がある。,改行文字(列)の変換も同時に行われる。,"¥r¥n" ==> "¥n",31 ==> "¥n" (31: AZ-Prologの改行コード),対象文字列オブジェクトに対する操作、検索結果のcapture(捕獲)文字列に改行が含まれる場合には、上記の改行コードの変換が行われたものが入っている。,5.検索対象文字列オブジェクトを開放する,onig_free_target_string(+TARGET_STRING),6.検索対象文字列オブジェクトの一部分を返す,onig_target_string_part(+TARGET_STRING, +START, +END, -PART_STRING),TARGET_STRING,検索対象文字列オブジェクト,START,開始位置 (先頭は0) バイト単位,END,終了位置 (この位置の文字は含まれない) バイト単位,PART_STRING,部分文字列 (AZ-Prologのリスト),この述語は検索に直接必要なわけではない。,7.正規表現検索を実行,1)onig_search/7,REGEX,正規表現オブジェクト,TARGET_STRING,検索対象文字列オブジェクト,START,検索開始位置 (先頭は0) バイト単位,END,検索終了位置 (文字列の終わりまでなら未定義でもよい) バイト単位,MSTART,マッチした文字列の開始位置 バイト単位,MEND,マッチした文字列の終了位置 バイト単位,CAPTURES,captureグループ(捕獲式集合)のcapture文字列のリスト,全くマッチしなかった場合には、失敗する。,!!! この述語は非決定性ではない。 !!!,captureグループの中で、マッチしていないグループに対しては文字列ではなく'non'というアトムがセットされる。,<例>正規表現が '(a+)|(b+)'、文字列が "bbbb aaaa"の場合、(b+)のほうにマッチして返るので、(a+)にはマッチしない。,この場合、CAPTURESには、[non, [98,98,98,98]]がセットされる。,2)onig_search_success/8,onig_search_success(+REGEX, +TARGET_STRING, +START, +END, -MSTART, -MEND,,-CAPTURES, -NEXT),REGEX, TARGET_STRING, START, END, CAPTURES: onig_search/7と同じ。,マッチしたとき,MSTART: onig_search/7と同じ,MEND: onig_search/7と同じ,NEXT: マッチした長さが0より大きいとき,--> MENDと同じ値,マッチした長さが0のとき,--> MENDの次の文字 (次の位置が文字列の範囲外なら、endアトム),マッチしなかったとき,MSTART: nonアトム,MEND: nonアトム,NEXT: endアトム,!!! この述語は非決定性ではない。 !!!,マッチしなくても失敗しない。,マッチしたとき、次の開始位置を返すので、文字列全体に対して繰り返して実行するとき便利。,※NEXTで、MENDの位置を返すというのは、全てのマッチの可能性を調べるのであれば正しくない。,しかし現実の処理としてはこれで十分。"}); htmllist.push({"file":"manuals/manual_oniguruma.html#oniguruma_5","title":"9-6-5.正規表現パターン文法","text":"9-6-5.正規表現パターン文法,1.正規表現パターン基本要素,¥,退避修飾 (エスケープ) 正規表現記号の有効/無効の制御,|,選択子,(...),式集合 (グループ),[...],文字集合 (文字クラス),2.文字,¥t,水平タブ,(0x09),¥v,垂直タブ,(0x0B),¥n,改行,(0x0A),¥r,復帰,(0x0D),¥b,後退空白,※ 文字集合内でのみ有効,(0x08),¥f,改頁,(0x0C),¥a,鐘,(0x07),¥e,退避修飾,(0x1B),¥nnn,八進数表現,符号化バイト値(の一部),¥xHH,十六進数表現,符号化,¥x{7HHHHHHH},拡張十六進数表現,コードポイント値,¥cx,制御文字表現,コードポイント値,¥C-x,制御文字表現,コードポイント値,¥M-x,超,(x|0x80) コードポイント値,¥M-¥C-x,超 + 制御文字表現,コードポイント値,3.文字種,.,任意文字 (改行を除く),¥w,単語構成文字Unicode以外の場合:,英数字, "_" および 多バイト文字。,Unicodeの場合:,General_Category -- (Letter|Mark|Number|Connector_Punctuation),¥W,非単語構成文字,¥s,空白文字,Unicode以外の場合:,¥t, ¥n, ¥v, ¥f, ¥r, ¥x20,Unicodeの場合:,0009, 000A, 000B, 000C, 000D, 0085(NEL),,General_Category -- Line_Separator,-- Paragraph_Separator,-- Space_Separator,¥S,非空白文字,¥d,10進数字,Unicodeの場合: General_Category -- Decimal_Number,¥D,非10進数字,¥h,16進数字 [0-9a-fA-F],¥H,非16進数字,Character Property,+ 全てのエンコーディングで有効,Alnum, Alpha, Blank, Cntrl, Digit, Graph, Lower,,Print, Punct, Space, Upper, XDigit, Word, ASCII,,+ EUC-JP, Shift_JISで有効,Hiragana, Katakana,+ UTF8, UTF16, UTF32で有効,Any, Assigned, C, Cc, Cf, Cn, Co, Cs, L, Ll, Lm, Lo, Lt, Lu,,M, Mc, Me, Mn, N, Nd, Nl, No, P, Pc, Pd, Pe, Pf, Pi, Po, Ps,,S, Sc, Sk, Sm, So, Z, Zl, Zp, Zs,,Arabic, Armenian, Bengali, Bopomofo, Braille, Buginese,,Buhid, Canadian_Aboriginal, Cherokee, Common, Coptic,,Cypriot, Cyrillic, Deseret, Devanagari, Ethiopic, Georgian,,Glagolitic, Gothic, Greek, Gujarati, Gurmukhi, Han, Hangul,,Hanunoo, Hebrew, Hiragana, Inherited, Kannada, Katakana,,Kharoshthi, Khmer, Lao, Latin, Limbu, Linear_B, Malayalam,,Mongolian, Myanmar, New_Tai_Lue, Ogham, Old_Italic, Old_Persian,,Oriya, Osmanya, Runic, Shavian, Sinhala, Syloti_Nagri, Syriac,,Tagalog, Tagbanwa, Tai_Le, Tamil, Telugu, Thaana, Thai, Tibetan,,Tifinagh, Ugaritic, Yi,4.量指定子,欲張り,?,1回または0回,*,0回以上,+,1回以上,{n,m},n回以上m回以下,{n,},n回以上,{,n},0回以上n回以下 ({0,n}),{n},n回,無欲,??,1回または0回,*?,0回以上,+?,1回以上,{n,m}?,n回以上m回以下,{n,}?,n回以上,{,n}?,0回以上n回以下 (== {0,n}?),強欲 (欲張りで、繰り返しに成功した後は回数を減らすような後退再試行をしない),?+,1回または0回,*+,0回以上,++,1回以上, ,({n,m}+, {n,}+, {n}+ は、ONIG_SYNTAX_JAVAでのみ強欲な指定子),例. /a*+/ === /(?>a*)/,5.錨,^,行頭,$,行末,¥b,単語境界,¥B,非単語境界,¥A,文字列先頭,¥Z,文字列末尾、または文字列末尾の改行の直前,¥z,文字列末尾,¥G,照合開始位置,6.文字集合,^...,否定 (最低優先度演算子),x-y,範囲 (xからyまで),[...],集合 (文字集合内文字集合),..&&..,積演算 (^の次に優先度が低い演算子),例. [a-w&&[^c-g]z] ==> ([a-w] and ([^c-g] or z)) ==> [abh-w],※ '[', '-', ']'を、文字集合内で通常文字の意味で使用したい場合には、これらの文字を'¥'で退避修飾しなければならない。,POSIXブラケット ([:xxxxx:], 否定 [:^xxxxx:]),Unicode以外の場合:,alnum,英数字,alpha,英字,ascii,0 - 127,blank,¥t, ¥x20,cntrl, ,digit,0-9,graph,多バイト文字全部を含む,lower, ,print,多バイト文字全部を含む,punct, ,space,¥t, ¥n, ¥v, ¥f, ¥r, ¥x20,upper, ,xdigit,0-9, a-f, A-F,word,英数字, "_" および 多バイト文字,Unicodeの場合:,alnum,Letter | Mark | Decimal_Number,alpha,Letter | Mark,ascii,0000 - 007F,blank,Space_Separator | 0009,cntrl,Control | Format | Unassigned | Private_Use | Surrogate,digit,Decimal_Number,graph,[[:^space:]] && ^Control && ^Unassigned && ^Surrogate,lower,Lowercase_Letter,print,[[:graph:]] | [[:space:]],punct,Connector_Punctuation | Dash_Punctuation | Close_Punctuation |,Final_Punctuation | Initial_Punctuation | Other_Punctuation |,Open_Punctuation,space,Space_Separator | Line_Separator | Paragraph_Separator |,0009 | 000A | 000B | 000C | 000D | 0085,upper,Uppercase_Letter,xdigit,0030 - 0039 | 0041 - 0046 | 0061 - 0066,(0-9, a-f, A-F),word,Letter | Mark | Decimal_Number | Connector_Punctuation,7.拡張式集合,(?#...),注釈,(?imx-imx),孤立オプション,i: 大文字小文字照合,m: 複数行,x: 拡張形式,(?imx-imx:式),式オプション,(式),捕獲式集合,(?:式),非捕獲式集合,(?=式),先読み,(?!式),否定先読み,(?<=式),戻り読み,(?<!式),否定戻り読み,戻り読みの式は固定文字長でなければならない。,しかし、最上位の選択子だけは異なった文字長が許される。,例. (?<=a|bc) は許可. (?<=aaa(?:b|cd)) は不許可,否定戻り読みでは、捕獲式集合は許されないが、非捕獲式集合は許される。,(?>式),原子的式集合,式全体を通過したとき、式の中での後退再試行を行なわない,(?<name›式),名前付き捕獲式集合,式集合に名前を割り当てる(定義する)。,(名前は単語構成文字でなければならない。),名前だけでなく、捕獲式集合と同様に番号も割り当てられる。,番号指定が禁止されていない状態 (10. 捕獲式集合 を参照)のときは、名前を使わないで番号でも参照できる。,複数の式集合に同じ名前を与えることは許されている。,この場合には、この名前を使用した後方参照は可能であるが、部分式呼出しはできない。,8.後方参照,¥n,番号指定参照 (n >= 1),¥k‹name›,名前指定参照,名前指定参照で、その名前が複数の式集合で多重定義されている場合には、番号の大きい式集合から優先的に参照される。,(マッチしないときには番号の小さい式集合が参照される),※ 番号指定参照は、名前付き捕獲式集合が定義され、かつ ONIG_OPTION_CAPTURE_GROUPが指定されていない場合には、禁止される。(10. 捕獲式集合 を参照),ネストレベル付き後方参照,¥k<name+n> n: 0, 1, 2, ...,¥k<name-n> n: 0, 1, 2, ...,後方参照の位置から相対的な部分式呼出しネストレベルを指定して、そのレベルでの 捕獲値を参照する。,例-1.,/¥A(?<a>|.|(?:(?<b>.)¥g<a>¥k<b+0>))¥z/.match("reer"),例-2.,r = Regexp.compile(<<'__REGEXP__'.strip, Regexp::EXTENDED),(?<element> ¥g<stag> ¥g<content>* ¥g<etag> ){0},(? <stag> < ¥g<name> ¥s* > ){0},(? <name> [a-zA-Z_:]+ ){0},(? <content> [^<&]+ (¥g<element> | [^<&]+)* ){0},(? <etag></ ¥k<name+1> >){0},¥g<element>,__REGEXP__,p r.match('<foo>f<bar>bbb</bar>f</foo>').captures,9.部分式呼a出し ("田中哲スペシャル"),¥g<name>,名前指定呼出し,¥g<n>,番号指定呼出し (n >= 1), ,※ 最左位置での再帰呼出しは禁止される。,例. (?<name>a|¥g<name>b) => error,(?<name›a|b¥g<name>c) => OK,※ 番号指定呼出しは、名前付き捕獲式集合が定義され、かつ ONIG_OPTION_CAPTURE_GROUPが指定されていない場合には、禁止される。 (10. 捕獲式集合 を参照),※ 呼び出された式集合のオプション状態が呼出し側のオプション状態と異なっているとき、呼び出された側のオプション状態が有効である。,例. (?-i:¥g<name>)(?i:(?<name>a)){0} は "A" に照合成功する。,10.捕獲式集合,捕獲式集合(...)は、以下の条件に応じて振舞が変化する。,(名前付き捕獲式集合は変化しない), ,case 1. /.../,(名前付き捕獲式集合は不使用、オプションなし),(...) は、捕獲式集合として扱われる。,case 2. /.../g,(名前付き捕獲式集合は不使用、オプション 'g'を指定),(...) は、非捕獲式集合として扱われる。,case 3. /..(?<name>..)../,(名前付き捕獲式集合は使用、オプションなし),(...) は、非捕獲式集合として扱われる。,番号指定参照/呼び出しは不許可。,case 4. /..(?<name>..)../G,(名前付き捕獲式集合は使用、オプション 'G'を指定),(...) は、捕獲式集合として扱われる。,番号指定参照/呼び出しは許可。,但し,g: ONIG_OPTION_DONT_CAPTURE_GROUP,G: ONIG_OPTION_CAPTURE_GROUP,('g'と'G'オプションは、ruby-dev MLで議論された。),これらの振舞の意味は、名前付き捕獲と名前無し捕獲を同時に使用する必然性のある場面は少ないであろうという理由から考えられたものである。,補記 1. 文法依存オプション,+ ONIG_SYNTAX_RUBY,(?m): 終止符記号(.)は改行と照合成功,+ ONIG_SYNTAX_PERL と ONIG_SYNTAX_JAVA,(?s): 終止符記号(.)は改行と照合成功,(?m): ^ は改行の直後に照合する、$ は改行の直前に照合する,補記 2. 独自拡張機能,+ 16進数数字、非16進数字 ¥h, ¥H,+ 名前付き捕獲式集合 (?‹name›...),+ 名前指定後方参照 ¥k<name>,+ 部分式呼出し ¥g<name>, ¥g,補記 3. Perl 5.8.0と比較して存在しない機能,+ ¥N{name},+ ¥l,¥u,¥L,¥U, ¥X, ¥C,+ (?{code}),+ (??{code}),+ (?(condition)yes-pat|no-pat),* ¥Q...¥E,但しONIG_SYNTAX_PERLとONIG_SYNTAX_JAVAでは有効,補記 4. Ruby 1.8 の日本語化 GNU regex(version 0.12)との違い,+ 文字Property機能追加 (¥p{property}, ¥P{Property}),+ 16進数字タイプ追加 (¥h, ¥H),+ 戻り読み機能を追加,+ 強欲な繰り返し指定子を追加 (?+, *+, ++),+ 文字集合の中の演算子を追加 ([...], &&),('[' は、文字集合の中で通常の文字として使用するときには退避修飾しなければならない),+ 名前付き捕獲式集合と、部分式呼出し機能追加,+ 多バイト文字コードが指定されているとき、文字集合の中で八進数または十六進数表現の連続は、多バイト符合で表現された 一個の文字と解釈される,(例. [¥xa1¥xa2], [¥xa1¥xa7-¥xa4¥xa1]),+ 文字集合の中で、一バイト文字と多バイト文字の範囲指定は許される。,ex. /[a-あ]/,+ 孤立オプションの有効範囲は、その孤立オプションを含んでいる式集合の終わりまでである,例. (?:(?i)a|b) は (?:(?i:a|b)) と解釈される、(?:(?i:a)|b)ではない,+ 孤立オプションはその前の式に対して透過的ではない,例. /a(?i)*/ は文法エラーとなる,+ 不完全な繰り返し範囲指定子は通常の文字列として許可される,例. /{/, /({)/, /a{2,3/,+ 否定的POSIXブラケット [:^xxxx:] を追加,+ POSIXブラケット [:ascii:] を追加,+ 先読みの繰り返しは不許可,例. /(?=a)*/, /(?!b){5}/,+ 数値で指定された文字に対しても、大文字小文字照合オプションは有効,例. /¥x61/i =~ "A",+ 繰り返し回数指定で、最低回数の省略(0回)ができる,/a{,n}/ == /a{0,n}/,最低回数と最大回数の同時省略は許されない。(/a{,}/),+ /a{n}?/は無欲な演算子ではない。,/a{n}?/ == /(?:a{n})?/,+ 無効な後方参照をチェックしてエラーにする。,/¥1/, /(a)¥2/,+ 無限繰り返しの中で、長さ零での照合成功は繰り返しを中断させるが、このとき、中断すべきかどうかの判定として、捕獲式集合の捕獲状態の変化まで考慮している,/(?:()|())*¥1¥2/ =~ "",/(?:¥1a|())*/ =~ "a",補記 5. 実装されているが、既定値では有効にしていない機能,+ 捕獲履歴参照,(?@...) と (?@‹name›...),例. /(?@a)*/.match("aaa") ==> [<0-1>, <1-2>, <2-3>],使用方法は、sample/listcap.cを参照,有効にしていない理由は、どの程度役に立つかはっきりしないため。,補記 6. 問題点,+ UTF-8で、バイト値が適正な価かどうかのチェックは行なっていない。,* 先頭バイトとして不正なバイトを一文字とみなす,/./u =~ "¥xa3",* 不完全なバイトシーケンスのチェックをしない,/¥w+/ =~ "a¥xf3¥x8ec",これを調べることは可能ではあるが、遅くなるので行なわない。"}); htmllist.push({"file":"manuals/manual_mecab-cabocha.html#mecab","title":"9-7-1.概要","text":"9-7-1.概要,AZ-Prolog から日本語処理解析エンジン、Mecab・CaboChaを利用するインターフェースを提供します。,2014年3月現在、OSによって提供範囲が次のようになっています。, ,Windows 32bit,Windows 64bit,Linux 32bit,Linux 64bit,Mac 64bit,Mecab,○,○,○,○,○,CaboCha,○,×,×,×,×,* AZ-Prolog Windows64bit版には mecabの64bit用ライブラリが付属しています(mecabのインストールは必要です)。,* これは、LGPLライセンス規約にのっとって弊社がコンパイルし再配布するものです。,* <参照URL>,* "http://www.ipentec.com/document/document.aspx?page=mecab-compile-for-x64-windows-use-x64-windows",AZ-Prolog とのインターフェースプログラムとMakefileは、AZPrologインストールDIR¥system¥ext¥mecab にあり、ユーザが修正、再コンパイルして.so .dll を生成することができます。,AZ-Prologからの利用サンプルは、AZPrologインストールDIR下にありますので、使い方の参考にしてください。,mecab.pl,cabocha.pl,★MeCab,MeCabは京都大学情報学研究科日本電信電話株式会社コミュニケーション科学基礎研究所共同研究ユニットプロジェクトを通じて開発された、オープンソース形態素解析エンジンです。,MecabHP:http://taku910.github.io/mecab/,★CaboCha,CaboChaは、奈良先端科学技術大学院大学および工藤拓氏によって開発された、オープンソースの日本語係り受け解析器です。,CaboChaHP:http://taku910.github.io/cabocha/"}); htmllist.push({"file":"manuals/manual_mecab-cabocha.html#mecab_2","title":"9-7-2.ライブラリのインストールと動作確認","text":"9-7-2.ライブラリのインストールと動作確認,[Windows],1) mecab (と cabocha)を前記URLからダウンロードし、インストールします。,2) 環境変数のシステムパスにインストールされた mecab¥bin cabocha¥binを追加します。,3) 64ビットWindowsの場合のみ、AZ-Prolog パッケージで提供している64bit用dllとlibを(1)のmecabインストール先にコピーします。AZPrologインストールDIR¥mecab64¥ にコピーバッチ "install.bat" がありますのでインストール先を確認し、必要なら書き換えて管理者として実行してください。,4) AZ-Prolog を立ち上げて拡張ライブラリを読み込み、テストプログラムを走らせてみます。,テストプログラムは AZPrologインストールDIRのsample¥ext¥mecab.pl,cabocha.plです。,> prolog,| ?- dlib_require(mecab).,yes,| ?- [-'C:¥azprolog.962¥sample¥ext¥mecab.pl'].,yes,| ?- t.,<テストプログラムの結果が出力されます>,yes,| ?- [-'C:¥azprolog.962¥sample¥ext¥cabocha.pl'].,yes,| ?- t.,<テストプログラムの結果が出力されます>,yes,[Linux],1) mecab をインストールします。,$ sudo apt-get update,$ sudo apt-get upgrade,$ sudo apt-get install mecab mecab-utils mecab-ipadic mecab-ipadic-utf8,2) AZ-Prolog を立ち上げて拡張ライブラリを読み込み、テストプログラムを走らせてみます。,テストプログラムは インストールDIRのsample/ext/mecab.plです。,$ prolog,| ?- dlib_require(mecab).,yes,| ?- [-'/usr/share/azprolog/sample/ext/mecab.pl'].,yes,| ?- t.,<テストプログラムの結果が出力されます>,yes,[MAC],1) mecab をインストールします。,$ sudo port install mecab,2) AZ-Prolog を立ち上げて拡張ライブラリを読み込み、テストプログラムを走らせてみます。,テストプログラムは インストールDIRのsample/ext/mecab.plです。,$ prolog,| ?- dlib_require(mecab).,yes,| ?- [-'/Applications/azprolog.app/Contents/az_home/share/azprolog/sample/ext/mecab.pl'].,yes,| ?- t.,<テストプログラムの結果が出力されます>,yes"}); htmllist.push({"file":"manuals/manual_mecab-cabocha.html#mecab_3","title":"9-7-3.Mecabインターフェース","text":"9-7-3.Mecabインターフェース,(1)インターフェース述語,用意している組込述語は、MeCabが提供しているC言語用のインターフェースに対応しているものが存在します。ただしmecab_nbest_end/0」は対応するものは存在しません。,MeCabのC言語用のインターフェースについては、MeCabのドキュメントの中の「doc/libmecab.html」ファイルに説明があります。,mecab_new(-MECAB, +ARGS),MeCabインスタンスを作成して、それをMECABに返す。,ARGSには、mecabコマンドの引数と同様の値を指定する。 (型は、アトムのリスト),mecab_strerror(+MECAB, -ERR),他のMeCab述語を実行中にエラーが発生したとき、エラー内容を示す文字列をアトムにした値を返す。,mecab_destroy(+MECAB),MeCabインスタンスを破棄/開放する。,mecab_sparse_tonode(+MECAB,+STATEMENT,+NODE_FORM_NUM,-NODE_LIST),あたえられた文(STATEMENT)を解析する。,結果をMeCabノードのリストとして返す(NODE_LIST)。ノード一個が一個の形態素に関する情報をもつ。,ただし、MeCabの特徴として、最初のノードは必ずBOSノードであり、最後は必ずEOSノードになる。,NODE_FORM_NUMはノードの中の情報量を指定するためのものである。 0から12までの整数を指定する。 ノードの値は複数の属性をもつので、それ自身がリストになっている。,(例外は、NODE_FORM_NUMを0に指定した場合のみ),<NODE_FORM_NUM>>,態素の表層文字列(アトム)のみを返す。,情報が一個だけなので、リストにしない。,(1を指定した場合にはリストになる),1 - 12: 指定した個数分の情報をリストにして返す。,12なら、全ての情報を返すことになる。,①: surface: 表層文字列 (アトム),②: stat: 形態素の種類を表すアトム,('MECAB_NOR'/'MECAB_UNK'/'MECAB_BOS'/'MECAB_EOS'),③: feature: 素性情報 (リスト) -- 後述,④: char_type: 文字種情報 (整数),⑤: isbest: ベスト解: 1, それ以外: 0,⑥: wcost: 単語生起コスト (Float),⑦: cost: 累積コスト (Float),⑧: alpha: forward backward の foward log 確率 (Float),⑨: beta: forward backward の backward log 確率 (Float),⑩: prob: 周辺確率 (Float),⑪: rcAttr: 右文脈 id (整数),⑫: lcAttr: 左文脈 id (整数),(* alpha, beta, prob は -l 2 オプションを指定した時に定義される),上記の順番で、リストが作成される。,例えば、NODE_FORM_NUMを4に指定すると、[SURFACE, STAT, FEATURE, CHAR_TYPE]のリストが、個々のノード毎に作成される。,素性情報は要素を9個もつリストである。 以下の要素をもつ。,[品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音],各要素は全てアトムである。,名詞なので活用がないなど、要素として値を持っていない部分には、'*'が 値として入る。,しかし、これはMeCab用のIPA辞書を使用した場合であって、これとはまったく異なる 内容を持った辞書を使用した場合には、数も意味も違う内容になると思われる。,mecab_nbest_end/0, mecab_nbest_init/2 の終了処理。,必ず一回呼び出す必要がある。,(これは、Prologインターフェースの内部処理上必要なものである),(2)注意点など,・ kanji mode offで実行してください。,:- kanji_mode(_,off).,・ 解析可能な文の最大バイト長は、2048です。,(AZMECAB_MAX_PARSE_STRING_LEN/azmecab.c)"}); htmllist.push({"file":"manuals/manual_mecab-cabocha.html#mecab_3","title":"9-7-4.CaboChaインターフェース","text":"9-7-4.CaboChaインターフェース,(1)インターフェース述語,用意している組込述語は、CaboChaが提供しているC言語用のインターフェースに、対応しているものが存在します。ただし「cabocha_tree_get_chunk_list/2」は対応するものは存在しません。,CaboChaのC言語用のインターフェースについては、CaboChaのドキュメントの中の「doc/libcabocha.html」ファイルに説明があります。,cabocha_strerror(+CABOCHA, -ERR),他のCaboCha述語を実行中にエラーが発生したとき、エラー内容を示す文字列をアトムにした値を返す。,cabocha_new(-CABOCHA, +ARGS),CaboChaインスタンスを作成して、それをCABOCHAに返す。,ARGSには、cabochaコマンドの引数と同様の値を指定する。 (型は、アトムのリスト),cabocha_destroy(+CABOCHA),CaboChaインスタンスを破棄/開放する。,cabocha_sparse_tonode(+CABOCHA, +STATEMENT, -RESULT),あたえられた文(STATEMENT)を解析する。,STATEMENTは、アトムかリストである。,結果を文字列として返す(RESULT)。,cabocha_sparse_totree(+CABOCHA, +STATEMENT, -RESULT_TREE),あたえられた文(STATEMENT)を解析する。,STATEMENTは、アトムかリストである。,結果を木構造のオブジェクト(整数)として返す(RESULT_TREE)。,cabocha_tree_size(+RESULT_TREE, -SIZE),木構造オブジェクトの要素数を返す。,要素数とは、文節数ではなく、形態素要素数である。,cabocha_tree_get_token(+RESULT_TREE, +AT, -TOKEN),木構造オブジェクトのAT番目(0から要素数-1まで)の要素の情報をリスト(TOKEN)で返す。,1: surface: 表層文字列 (アトム),2: base 基本形 (アトム),3: read 読み (アトム),4: pos_list  品詞情報 アトムリスト (最大8個まで),5: cform 活用形 (アトム),6: ctype 活用型 (アトム),7: ne ? 名詞に関する何かの情報 (B-ORGNIZATIONなど),8: optional 付加情報 (アトム),9: status ? (整数),上記の順番で、リストが作成される。,cform, ctype, ne, optionalについては、値がないときには、'*'が値として入る。,cabocha_tree_get_chunk_list(+RESULT_TREE, -CHUNK_LIST),木構造オブジェクトから、文節情報/文節係り受け情報のリスト(CHUNK_LIST)を返す。,CHUNK_LISTの各要素はそれぞれ一個の文節に関する情報である。,文節の順序は、元の文に現れた順序のままである。,各文節情報は、以下の要素を持つリストである。,1: link 係り先文節番号 (0から),2: head 主辞形態素番号 (文節内、0から),3: func 機能形態素番号 (文節内、0から),4: rel 係り種別 ('D': 依存),5: score ?,6: feature_list 解析中、文節に付加された特性(アトム)のリスト,7: token_list 文節に含まれる形態素の情報のリスト,(個々の形態素情報は、cabocha_tree_get_token/3で返されるものと同じ),(2)注意点など,・ kanji mode offで実行してください。,:- kanji_mode(_,off).,・ 解析可能な文の最大バイト長は、2048である。,(AZCABOCHA_MAX_PARSE_STRING_LEN/azcabocha.c)"}); htmllist.push({"file":"manuals/manual_socket.html#socket","title":"9-8-1.概要","text":"9-8-1.概要,ネットワーク通信プロトコル(TCP/IP)を利用したクライアントとサーバー間のネットワーク接続についてインターフェースを提供します。,以下に、インターフェースとして提供する述語と概要及びAZ-Prolog Version7でのプラットフォーム別サポート状況を示します。, ,述語インターフェース名,概要説明,通常(※1),Windows,Linux/Mac,A, server_create/2 , server_create/3 ,ソケットサーバーを生成します,○,○,○, server_accept/3 ,クライアントからの接続要求時に接続を確立します,○,○,○, client_connect/3 ,ソケット接続の接続要求を行います,○,○,○, client_connect_async/3 ,ソケット接続の接続要求を非同期で行います,○,×,○, socket_send/2 ,ソケットにデータを送信します,○,○,○, socket_send_list/2 ,ソケットにリストを送信します,○,○,○, socket_receive/2 ,ソケットからデータを受信します,○,○,○, socket_receive_list/2 ,ソケットからリストを受信します,○,○,○, socket_close/1 ,ソケット接続を終了します,○,○,○, select_from_sockets/3 ,ソケットリストからデータを受信しているソケットを抽出します,○,○,○, host2ip/4 ,ホスト名をIPアドレスに変換します,○,○,○,B, ssl_client_connect/4,SSLソケット接続の接続要求を行います, ,○,○,ssl_socket_send/2,SSLソケットにデータを送信します, ,○,○, ssl_socket_receive/2 ,SSLソケットからデータを受信します, ,○,○, ssl_socket_close/1 ,SSLソケット接続を終了します, ,○,○,C, ssl_cert_load_cafile/3 ,サーバー証明書ファイル(CA)で認証を行いソケット接続を確立します, ,○,○, ssl_cert_load_file/4 ,サーバー証明書ファイル(CA)と秘密鍵ファイル(Private Key)で認証を行いソケット接続を確立します, ,○,○, ssl_cert_load_data/4 ,サーバー証明書データ(CA)と秘密鍵データ(Private Key)で認証を行いソケット接続を確立します, ,○,○, ssl_cert_send/2 ,認証されたソケットにデータを送信します, ,○,○, ssl_cert_receive/3 ,認証されたソケットからデータを受信します, ,○,○, ssl_cert_close/1 ,SSLコンテキストを解放します。, ,○,○,D, socket_download/2 ,ソケットからデータを受信しファイルへ書き込みます,○,○,○, socket_ssl_download/2 ,SSLソケットからデータを受信しファイルへ書き込みます, ,○,○,E, unix_client_connect/2 ,UNIXソケットよりソケット接続の接続要求を行います,○,×,○, unix_server_create/2 ,UNIXソケットよりソケットサーバーを生成します,○,×,○, unix_server_close/2 ,UNIXソケットでのソケット接続を終了します,○,×,○,F, check_socket_receivable/1 ,ソケットに読み込みデータがあるかを確認します,○,○,○, check_socket_sendable/1 ,ソケットディスクリプタの接続確立状況を確認します,○,○,○,G, ping/2 ,ネットワーク疎通を確認します,○,×,○, ping_async/2 ,ネットワーク疎通確認をソケットを通して行います,○,×,○,H, ws_set_log_level/1 ,libwebsocketsのログ出力レベルを指定する,○,×,○, ws_set_client_certificate_file_path/1 ,クライアント側certificate fileのパスを指定する,○,×,○, ws_set_client_private_key_file_path/1 ,クライアント側private key fileのパスを指定する,○,×,○, ws_create_context/3 ,クライアント側のCONTEXTを生成する,○,×,○, ws_delete_context/1 ,CONTEXTを削除する,○,×,○, ws_connect/10 ,サーバに接続して、生成されたSESSIONを返す,○,×,○, ws_close/1 ,接続SESSIONを閉じる,○,×,○, ws_is_close/2 ,接続SESSIONを閉じる,○,×,○, ws_sub_protocol/2 ,指定されたSESSIONのsub-protocolを返す,○,×,○, ws_read_text/3 ,テキストデータを読み込む,○,×,○, ws_write_text/2 ,テキストデータを送信する,○,×,○, ws_write_atom_list/2 ,アトム並びリストのテキストデータを送信する,○,×,○, ws_read_list/3 ,バイナリデータを読み込む,○,×,○, ws_write_list_binary/2 ,バイナリデータを送信する,○,×,○, ws_write_pong/1 ,PONGを送信する,○,×,○, ws_version/1 ,バージョン情報を取得する,○,×,○,   ※1) 通常とはOpenSSLライブラリ、Cryptoライブラリがインストールされていない状態を示します。,上記一覧で示している述語は、8つのグループ(A~H)に分けられます。,Aグループ,通常ソケット関連述語,Bグループ,SSLソケット関連述語,Cグループ,証明書認証関連述語,Dグループ,ファイルダウンロード関連述語,Eグループ,UNIXソケット関連述語,Fグループ,読込みデータ及び接続の確認関連述語,Gグループ,疎通確認関連述語,Hグループ,WEBソケット関連述語,コンパイルされたダイナミックローディングライブラリは次です。,[Windows],${AZProlog} = インストールディレクトリ,${AZProlog}¥lib¥ext¥socket.dll,${AZProlog}¥lib¥ext¥socket_ssl.dll,[Linux],${AZProlog} = /usr/local またはインストールディレクトリ,${AZProlog}lib/azprolog/ext/socket.so,${AZProlog}lib/azprolog/ext/socket_ssl.so,${AZProlog}lib/azprolog/ext/websock.so,[Mac],${AZProlog} = /Applications/azprolog.app/Contents/az_home/ またはインストールディレクトリ,${AZProlog}lib/azprolog/ext/socket.dylib,${AZProlog}lib/azprolog/ext/socket_ssl.dylib,${AZProlog}lib/azprolog/ext/websock.dylib"}); htmllist.push({"file":"manuals/manual_socket.html#socket_2","title":"9-8-2.インストール","text":"9-8-2.インストール,Windowsの場合,OpenSSLをインストールする場合は、OpenSSLサイトよりインストーラーをダウンロードし起動してインストールを行います。,Cryptoをインストールする場合は、Cryptoサイトよりライブラリまたはコンパイルソース一式をダウンロードします。,なお、コンパイルソース一式をダウンロードする場合は、コンパイルを実施しライブラリの生成を行います。,※ライブラリ生成後は、Windowsシステム・ディレクトリ(WindowsSystem32)にコピーします。,【OpenSSLのダウンロード】,http://slproweb.com/products/Win32OpenSSL.html,Win32 OpenSSL v1.0.2,または,Win64 OpenSSL v1.0.2,【Cryptoのダウンロード】,http://www.cryptopp.com/#download,バイナリのダウンロードは、サイトの中ごろにあるリンクをクリックして行います。,「FIPS 140-2 Conformance」,・Crypto++ Library 5.3.0 (32-bit and 64-bit Windows DLL, calling application must be compiled with MSVC 2005) [download package] [download PGP signature] [certificate #819],→[download package]のリンクをクリックします。(2015.03.09現在でバージョンは5.3.0が最新です),インストール後は、以下に示すライブラリファイルが Windowsシステム・ディレクトリ(WindowsSystem32)に存在するか確認します。もし、1つでもライブラリファイルが存在しない場合は、ライブラリのロード述語で失敗する可能性があります。,- ssleay32.dll,- libeay32.dll,- cryptopp.dll,Linuxの場合,$ sudo apt-get install openssl,$ sudo apt-get install libssl-dev,Macの場合,$ sudo port install openssl"}); htmllist.push({"file":"manuals/manual_socket.html#socket_3","title":"9-8-3.動作確認","text":"9-8-3.動作確認,通常ソケットの場合,AZ-Prolog を立ち上げ、ソケットライブラリがロードできるか確認します。,$ prolog,| ?-dlib_require(socket).,yes,| ?-,通常ソケット関連の述語を利用する場合は、上記のように必ず dlib_require で socket ライブラリをロードしてください。,WEBソケットの場合,AZ-Prolog を立ち上げ、ソケットライブラリがロードできるか確認します。,$ prolog| ?-dlib_require(websock).yes| ?-,WEBソケット関連の述語を利用する場合は、上記のように必ずdlib_requireで、websockライブラリをロードしてください。,SSLソケットの場合,AZ-Prolog を立ち上げ、SSLソケットライブラリがロードできるか確認します。,$ prolog,| ?-dlib_require(socket_ssl).,yes,| ?-,SSLソケット関連の述語を利用する場合は、上記のように必ず dlib_require でsocket_ssl ライブラリをロードしてください。,なお、通常またはSSLソケットライブラリのロードを行ってもプラットフォームで利用できる述語が異なりますので御注意ください。,「9-8-1.概要」の表(サポート状況)を参照ください。"}); htmllist.push({"file":"manuals/manual_socket.html#socket_4","title":"9-8-4.述語の組み合せ利用例","text":"9-8-4.述語の組み合せ利用例,ソケット関連の述語は単独で利用できないものが多く、組み合せで利用しなければなりません。,述語の組み合せ利用例として以下に紹介します。,Aグループ:通常ソケット関連述語,ソケットサーバー生成とクライアント接続の述語記述例,<サーバー側>,ソケットサーバーを生成する,使用述語: server_create、select_from_sockets、server_accept、socket_receive_list,go:-server_create('5000',Acc),,repeat,,all_acc(1,WatchList),,select_from_sockets(20000,[Acc|WatchList],ReceivedList),,member(Sock,ReceivedList),,rec_do(Acc,Sock,Data),,write(Sock=Data),nl,,fail.,rec_do(A,A,_):- !,server_accept(A,Host,S),assert('$acc$'(S)),fail.,rec_do(_,S,D):- socket_receive_list(S,D),length(D,N),N>0,!.,rec_do(_,S,_):- socket_close(S),retract('$acc$'(S)),fail.,all_acc(N,[A|L]):- clause('$acc$',1,N,'$acc$'(A)),!,NN is N+1,all_acc(NN,L).,all_acc(_,[]).,?-go.,4=[97,98,99,100,101,102,103,13,10],ソケットサーバーのサーバー生成述語を定義し、その後述語を実行しクライアントからの接続待機を行う。,上記の例ではソケットサーバーを5000ポートで生成し、クライアントからの接続を待機する。,その後、クライアントからの接続が確立された場合は、データ受信を行い受信データをリストで表示している。,クライアント側で接続を試す,$ telnet localhost 5000,Trying 127.0.0.1...,Connected to localhost.,Escape character is '^]'.,abcdefg,telnetコマンドでソケットサーバー(localhost)に5000ポートで接続し データ(abcdefg) を入力,<クライアント側:同期>,ソケットサーバーに接続しデータを送信する,使用述語: client_connect、socket_send、socket_close,test:-,client_connect('127.0.0.1','5000',S),,socket_send(S,'TEST'),,socket_close(S).,?-test.,yes,?-,ソケットサーバーへ接続しデータを送信する述語を定義し、その後述語を実行しソケットサーバーへデータを送信する。,上記の例では、ソケットサーバー(127.0.0.1)に5000ポートで接続しデータを送信している。,Web上のコンテンツを取得する,使用述語: client_connect、socket_send、socket_from_sockets、socket_receive_list、socket_close,get_request(Url):-,client_connect('127.0.0.1','80',S),,name(CR,[10]),,atom_concat('GET ',Url,P1),,atom_concat(P1,' HTTP/1.1',P2),,atom_concat(P2,CR,P3),,atom_concat(P3,'Host: 127.0.0.1',P4),,atom_concat(P4,CR,P5),,atom_concat(P5,'Connection: Close',P6),,atom_concat(P6,CR,P7),,atom_concat(P7,CR,Get),,socket_send(S,Get),,get_all(S,"""",LAns),,socket_close(S),,name(Ans,LAns),,write(Ans).,get_all(Sock2,Bef,Ans):-,select_from_sockets(20000,[Sock2],[Sock3]),,socket_receive_list(Sock3,Out),length(Out,N),N>0,!,,append(Bef,Out,NextBef),,get_all(Sock3,NextBef,Ans).,get_all(Sock2,A,A).,?-get_request('/index_test.html').,HTTP/1.1 200 OK,Date: Mon, 02 Dec 2013 09:33:50 GMT,Server: Apache/2.2.22 (Ubuntu),Last-Modified: Mon, 02 Dec 2013 09:29:57 GMT,ETag: ""161652-2d-4ec89d2c4b7a4"",Accept-Ranges: bytes,Content-Length: 45,Vary: Accept-Encoding,Connection: close,Content-Type: text/html,‹html›,‹body›,Test Test Test,‹/body›,‹/html›,yes,?-,WEBサーバーからGETリクエストでコンテンツを取得する述語を定義し、その後述語を実行し取得したコンテンツを表示する。,上記の例ではWEBサイト(127.0.0.1)にHttpポート(80)で接続し、GETリクエストで指定のコンテンツを取得し表示している。,Proxy経由でWeb上のコンテンツを取得する,使用述語: client_connect、socket_send、socket_from_sockets、socket_receive_list、socket_close,get_from_proxy(Url):-,client_connect('127.0.0.1','3128',S),,name(CR,[10]),,atom_concat('GET ',Url,P1),,atom_concat(P1,' HTTP/1.1',P2),,atom_concat(P2,CR,P3),,atom_concat(P3,'Host: 127.0.0.1',P4),,atom_concat(P4,CR,P5),,atom_concat(P5,'Connection: Close',P6),,atom_concat(P6,CR,P7),,atom_concat(P7,CR,Get),,socket_send(S,Get),,get_all(S,"""",LAns),,socket_close(S),,name(Ans,LAns),,write(Ans).,get_all(Sock2,Bef,Ans):-,select_from_sockets(20000,[Sock2],[Sock3]),,socket_receive_list(Sock3,Out),length(Out,N),N>0,!,,append(Bef,Out,NextBef),,get_all(Sock3,NextBef,Ans).,get_all(Sock2,A,A).,?-get_from_proxy('http://www.yahoo.co.jp').,HTTP/1.0 200 OK,Date: Mon, 02 Dec 2013 09:11:33 GMT,P3P: policyref=""http://privacy.yahoo.co.jp/w3c/p3p.xml"", CP=""CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"",Expires: -1,Pragma: no-cache,Cache-Control: private, no-cache, no-store, must-revalidate,X-XRDS-Location: http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds,Vary: Accept-Encoding,Content-Type: text/html; charset=utf-8,X-Cache: MISS from localhost,X-Cache-Lookup: MISS from localhost:3128,Via: 1.0 localhost (squid/3.1.19),Connection: close, ・   , ・   , ・   ,‹/body›,‹/html›,yes,?-,Proxyサーバー経由でWEBサーバーからGETリクエストでコンテンツを取得する述語を定義し、その後述語を実行し取得したコンテンツを表示する。,上記の例ではProxyサーバー(127.0.0.1)経由でWebサイト(localhost)にHttpポート(80)で接続し、GETリクエストで指定のコンテンツを取得し表示している。,Bグループ:SSLソケット関連述語,SSLソケットクライアント接続の述語記述例,SSLソケットでWeb上のコンテンツを取得する,使用述語: ssl_client_connect、ssl_socket_send、ssl_socket_receive、ssl_socket_close,get_ssl_request(Host):-,host2ip(Host,GH,AH,IP),,ssl_client_connect(IP,'443','RSA',S),,name(C,[10]),,D1 = 'GET / HTTP/1.1',,atom_concat(D1,C,D2),,atom_concat(D2,'Host: ',D3),,atom_concat(D3,Host,D4),,atom_concat(D4,':443',D5),,atom_concat(D5,C,D6),,atom_concat(D6,'Connection: Close',D7),,atom_concat(D7,C,D8),,atom_concat(D8,C,Data),,ssl_socket_send(S,Data),,get_all(S,"""",LAns),,name(Ans,LAns),,write(Ans),nl,,ssl_socket_close(S).,get_all(Sock2,Bef,Ans):-,ssl_socket_receive(Sock2,Out),name(Out,OutL),length(OutL,N),N>0,!,,append(Bef,OutL,NextBef),,get_all(Sock2,NextBef,Ans).,get_all(Sock2,A,A).,?-get_ssl_request('www.verisign.co.jp').,HTTP/1.1 200 OK,Server: """",Date: Mon, 02 Dec 2013 05:51:28 GMT,Content-type: text/html,Connection: close,‹!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"" ""http://www.w3.org/TR/html4/loose.dtd""›,‹html lang=""ja""›,‹head›,‹link rel=""canonical"" href=""https://www.verisign.co.jp/""›,・   ,・   ,・   ,‹/body›,‹/html›,yes,?-,指定されたホストにSSLで接続し、GETリクエストでコンテンツを取得する述語を定義し、その後述語を実行し取得したコンテンツを表示する。,上記の例ではベリサインのサイト(www.verisign.co.jp)にSSLで接続し、GETリクエストでトップサイトのコンテンツを取得し表示している。,Cグループ:証明書認証関連述語,サーバー証明書ファイル(CA)で認証し、ソケットクライアント接続の述語記述例,サーバー証明書ファイル(CA)で認証し、ソケットクライアント接続を行ってデータの送受信を行う,使用述語: client_connect、ssl_cert_load_cafile、ssl_cert_send、ssl_cert_receive、socket_close、ssl_cert_close,test:-,IP='127.0.0.1',,CERT_FILE='server.pem',,client_connect(IP,'3000',S),,ssl_cert_load_cafile(S,CERT_FILE,S2),,name(C,[10]),,Data1='Get Data Request',,atom_concat(Data1,C,Data),,ssl_cert_send(S2,Data),,get_all(S2,"""",LAns),,name(Ans,LAns),,write(Ans),nl,,socket_close(S),,ssl_cert_close(S2).,get_all(SN,Bef,Ans):-,ssl_cert_receive(SN,Out,Sz),name(Out,OutL),length(OutL,N),N>0,!,,append(Bef,OutL,NextBef),,get_all(SN,NextBef,Ans).,get_all(SN,A,A).,?-test.,Welcome !! Test Certificate Data,yes,?-,ソケットサーバーに認証接続を行いデータの送受信を行う述語を定義し、その後述語を実行し受信データを表示する。,上記の例ではソケットサーバー(localhost)にクライアント接続し証明書ファイル認証を行い、その後データの送受信を行って受信データを表示している。,Dグループ:ファイルダウンロード関連述語,ソケットサーバーからファイルをダウンロードする述語記述例,ソケットサーバーよりバイナリファイルをダウンロードする,使用述語: client_connect、socket_send、socket_download、socket_close,test:-,client_connect('127.0.0.1','80',S),,P1='GET /icon.zip HTTP/1.1',,name(C,[10]),,atom_concat(P1,C,P2),,atom_concat(P2,'Host: 127.0.0.1',P3),,atom_concat(P3,C,P4),,atom_concat(P4,'Connection: Close',P5),,atom_concat(P5,C,P6),,atom_concat(P6,C,Get),,socket_send(S,Get),,socket_download(S, 'icon.zip'),,socket_close(S).,?-test.,yes,?-,ソケットサーバーにクライアント接続しGETリクエストでファイルをダウンロードする述語を定義し、その後述語を実行しファイルをダウンロードする。,上記の例ではWebサイト(localhost)にHttpポート(80)で接続し、GETリクエストでバイナリファイルをダウンロードしている。,Eグループ:UNIXソケット関連述語,UNIXソケットサーバー生成とクライアント接続の述語記述例,<サーバー側>,UNIXソケットサーバーを生成する,使用述語: unix_server_create、select_from_sockets、socket_send、server_accept、socket_receive_list、socket_close,go:-unix_server_create('/tmp/test.sock',Acc),,repeat,,all_acc(1,WatchList),,select_from_sockets(20000,[Acc|WatchList],ReceivedList),,member(Sock,ReceivedList),,rec_do(Acc,Sock,Data),,write(Sock=Data),nl,,name(AData,Data),,socket_send(Sock,AData),,fail.,rec_do(A,A,_):- !,server_accept(A,Host,S),assert('$acc$'(S)),fail.,rec_do(_,S,D):- socket_receive_list(S,D),length(D,N),N>0,!.,rec_do(_,S,_):- socket_close(S),retract('$acc$'(S)),fail.,all_acc(N,[A|L]):- clause('$acc$',1,N,'$acc$'(A)),!,NN is N+1,all_acc(NN,L).,all_acc(_,[]).,?-go.,4=[72,101,108,108,111],UNIXソケットサーバーのサーバー生成述語を定義し、その後述語を実行しクライアントからの接続待機を行う。,上記の例ではUNIXソケットサーバーをUNIXソケット(/tmp/test.sock)で生成し、クライアントからの接続を待機する。,その後、クライアントからの接続が確立された場合は、データ受信を行い受信データをリストで表示しクライアント側へ受信データを返信している。,<クライアント側>,UNIXソケットサーバーに接続しデータを送受信する,使用述語: unix_client_connect、socket_send、select_from_sockets、socket_receive_list、socket_close,test:-,unix_client_connect('/tmp/test.sock',S),,socket_send(S,'Hello'),,get_all(S,"""",LAns),,name(Ans,LAns),,write(Ans),nl,,socket_close(S).,get_all(Sock2,Bef,Ans):-,select_from_sockets(20000,[Sock2],[Sock3]),,socket_receive_list(Sock3,Out),length(Out,N),N>0,!,,append(Bef,Out,NextBef),,get_all(Sock3,NextBef,Ans).,get_all(Sock2,A,A).,?-test.,Hello,yes,?-,UNIXソケットサーバーへ接続しデータを送受信する述語を定義し、その後述語を実行しUNIXソケットサーバー間でデータの送受信を行う。,上記の例では、UNIXソケット(/tmp/test.sock)でUNIXソケットサーバーに接続しデータを送信している。,その後、UNIXソケットサーバーからのデータを受信し、受信データを表示している。,Fグループ:データの送受信のノンブロッキング処理,ソケットのノンブロッキング処理の記述例,ノンブロッキング処理で送信、受信を行う,使用述語: client_connect、check_socket_sendable、socket_send、check_socket_receivable、socket_receive、socket_close,test:-,client_connect('127.0.0.1','5000',S),,repeat,,s_sleep(100),,check_socket_sendable(S),,socket_send(S,'Client Data'),,repeat,,s_sleep(100),,check_socket_receivable(S),,socket_receive(S,Data),,write(Data),nl,,socket_close(S).,?-test.,Server Data,yes,?-,上の項目まで説明してきたsendやreceiveなどは、全てブロッキング処理になり、sendの場合は「相手が受信できる状態までブロックする」、receiveの場合は「相手からのデータが届くまでブロックする」。,一つのソケットのやり取りを行うのであれば、ブロッキング処理でも問題ありませんが、複数のソケットを受信する場合や、受信待ちの間に別の作業を挟みたい場合はノンブロッキング処理を使用する必要があります。,check_socket_sendable(S),socket_send の前に置き、相手が受信できない状態であればfailする。相手が受信可能であれば成功し、次に続くsend処理もノンブロッキングで実施される。,check_socket_receivable(S),socket_receive の前に置き、ソケット宛の受信データが来ていない場合はfailする。受信データがあれば成功し、receive処理が実施できる。,上記の例では、ソケットサーバー(127.0.0.1)に5000ポートで接続し、接続後送信可能確認を行い、送信できる状態であればデータ送信、出来なければsleepしながら繰り返し送信確認。,送信後、受信データがデータを受信、なければsleepしながら繰り返し受信確認、データの受信後、データを表示している。,注意) 現在ノンブロッキング処理は非SSLのAグループとEグループでしか使用できません。,Gグループ:疎通確認関連述語,ネットワーク上のサーバー疎通確認述語記述例,ICMPを使用したサーバーの疎通確認を行う,使用述語:ping、ping_async、check_socket_receivable、socket_close,test1:-,ping('127.0.0.1',2).,?-test1.,yes,test2:-,ping_async('127.0.0.1',S),,repeat,,s_sleep(100),,check_socket_receivable(S),,socket_receive_list(S,L),,write(receive=L),nl,,length(L,Len),,(Len > 0->write('Replay');write('No Replay')),,socket_close(S).,?-test2.,receive=[69,0,0,28,140,241,64,0,64,1,175,237,127,0,0,1,127,0,0,1,8,0,247,255,0,0,0,0],Replay,yes,?-,ping(Server,Timeout)はサーバーに対しpingを実施、Timeout(秒)値以内で応答があれば成功し、なければfailします。,ping_async(Server,Socket)はICMPを送るとともにソケットを生成、ノンブロッキング処理で相手からの応答を待ちます。,そのため、ping_asyncの場合はソケット生成後の受信処理、終了処理を必要とします。,上記の例では、1つ目の述語が2秒のタイムアウトでpingの疎通確認を行う。2つ目の述語はソケットの生成を行いながらICMPの送信、,受信はcheck_socket_receivableが成功するまでs_sleepしながら待ち、受信確認ができれば受信データの表示をしている。,注意)ping処理はroot権限でないと使用ができません。,Hグループ:WEBソケット関連述語,WEBソケットサーバー生成とクライアント接続例,<サーバー側>,nodejsがインストールされていない場合はインストールしておきます。,ダウンロードサイト:http://nodejs.org/,$ cp ~/ダウンロード/node* .,$ tar xzf node-v0.10.26.tar.gz,$ cd node-v0.10.26,$ ./configure,$ make,$ sudo make install,パッケージにはnodejsを使ったサーバーのサンプルが含まれています。,これを任意の場所にコピーし、ここにwebsocketモジュールをインストールします,$ cp -r /usr/local/share/azprolog/sample/ext/websock_node_server .$ cd websock_node_server$ npm install websocket,SSLを使用しない場合のサーバー立ち上げ,$ node sample.js,SSL使用、クライアント認証付きのサーバー立ち上げ,$ node sample-client-cert.js,<クライアント側>,パッケージにAZ-PrologのWebソケットを使ったクライアントのサンプルが含まれています。,$ cd /usr/local/share/azprolog/sample/ext/$ prolog -s websock.pl| ?- t. % ssl を使用しない場合 <サーバーとの通信テストが開始され、画面に内容が表示されます。> :| ?- t2. % SSL使用、クライアント認証付き <サーバーとの通信テストが開始され、画面に内容が表示されます。>,処理のそれぞれの詳細はプログラムをご一読ください。"}); htmllist.push({"file":"manuals/manual_redis.html#redis","title":"9-9-1.概要","text":"9-9-1.概要,主流になりつつある、KVS(key value store)方式のデータベースの一つRedisのインターフェースです。,インターフェースソースは次にあります。READMEもご参照ください。,${AZProlog}/share/azprolog/system/ext/redis,また、コンパイルされたダイナミックローディングライブラリは次です。,${AZProlog}/lib/azprolog/ext/redis.so,Redisを使ったサンプルプログラムは次にあります。,${AZProlog}/share/azprolog/sample/ext/redis.pl"}); htmllist.push({"file":"manuals/manual_redis.html#redis_2","title":"9-9-2.Redisのインストール(Windows)","text":"9-9-2.Redisのインストール(Windows),1.次のサイトより、"hiredis.dll" "hiredis.lib" をダウンロードする,https://github.com/malkia/ufo/tree/master/bin/Windows/x64,https://github.com/malkia/ufo/tree/master/bin/Windows/x86,2.hiredis(ソース)のWindows版をダウンロードし解凍,次のサイトより、hiredisのWindows版をダウンロードする(32bit,64bitとも同じ)。,https://github.com/texnician/hiredis-win32,3.コンパイル環境の作成,前記ダウンロードしたhiredisのインクルードファイルとライブラリを任意の場所にコピーする。,ここでは、C:¥redis を例としてあげる。,このなかに、include と lib のディレクトリを作成する。,[インクルードファイル],2.でダウンロードしたredisソース内の "hiredis.h" 及び "adapters" をディレクトリごと include にコピー。,[ライブラリ],1.でダウンロードしたライブラリ "hiredis.lib" を lib にコピー。,C:¥redis¥include¥hiredis.h,|    |,|    ¥adapters,|,¥lib¥hiredis.lib,[ダイナミックリンクライブラリ],1.でダウンロードしたダイナミックリンクライブラリ(hiredis.dll)を C:Windows¥System32や%AZProlog%¥binなど,パスが設定されているディレクトリにコピーする。,4.コンパイル(Prolog用redisライブラリの作成),本ディレクトリにあるMakefileを環境に合わせ書き換える。現在の内容は、前記<例>にそった場所が書かれている,nmakeを実行し、nmake installでインストールする。,5.redis-server のダウンロードと起動,次のサイトより、Redis-Server をダウンロード、インストールする(32bit,64bit別のインストーラファイルがある)。,https://github.com/rgl/redis/downloads,[コントロールパネル]->[システムとセキュリティ]->[管理ツール]->[サービス] からRedis Server の開始をおこなう。,6.テスト,prologを実行しredisテストを行う。,> cd %AZProlog%sampleext,> prolog -s redis.pl,| ?- t.,:,(メッセージ表示),:,最後にOKが表示されれば正常終了です。"}); htmllist.push({"file":"manuals/manual_redis.html#redis_3","title":"9-9-3.Redisのインストール(Linux)","text":"9-9-3.Redisのインストール(Linux),1.インストール,$ sudo apt-get install redis-server,$ sudo apt-get install libhiredis-dev,AZ-Prolog のインストールにおいては、AZ-Prolog パッケージの解凍ディレクトリで次のコマンドを,投入します。,$ sudo make install_hiredis,または、websocket 、AZ-Prologのパッケージも同時にインストールするには,$ sudo make install_full,2.動作確認,AZ-Prolog を立ち上げ、前記サンプルプログラムを読み込み、述語「t/0」を質問します。,$ prolog -s /usr/local/share/azprolog/sample/ext/redis.pl| ?- t."}); htmllist.push({"file":"manuals/manual_odbc.html#odbc","title":"9-10-1.ODBC 機能の利用方法","text":"9-10-1.ODBC 機能の利用方法,(1)Windows ODBC データソースの設定,Windowsのスタート→コントロールパネル→管理ツール→データソース(ODBC)→システムDSNタブでAccess,SQLサーバなどのODBC・DSN(データソースネーム)を追加します。,設定内容の詳細はODBCに関するマニュアル、ヘルプなどをお調べください。,64ビットOSでは、64ビット用ODBCが組み込まれている必要があります。,64ビット用AccessのODBCドライバが組み込まれていない場合、下記からランタイムをインストールできます。(2015年3月現在),http://www.microsoft.com/ja-jp/download/details.aspx?id=39358,ここでは、DSN、ユーザ、パスワードすべて、"test"という文字列で設定された前提のプログラムとなっています。異なる場合は、次のステップの sql_connect_data/4 を必要に応じて書き換えます,(2)ユーザー定義単位節 DSNのProlog定義,1.で設定したDSNをProlog単位節で定義し、データベースの接続時に利用します。これ以降がPrologプログラムです。,書式,sql_connect_data(DSN識別子,DSN,User,Password).,第一引数DSN識別子は、SQL発行時に該当する sql_statement/3  の第一引数とユニフィケーションされるものが採用されます。複数のDSNを利用する場合、これを考慮した対応がとれるようにしてください。ここの例ではひとつのDSNしか利用していませんので、無名変数としていますが、DSN を複数利用し、SQL文を対応付けるには以下のようにでもすればよろしいでしょう。,sql_connect_data(sqlsv(_) ,"sqlsv_dsn" ,....,sql_connect_data(access(_) ,"access_dsn",....,sql_statement(sqlsv(1),,sql_statement(sqlsv(2),,sql_statement(access(1),  ,DSN識別子 DSN名 User Password,sql_connect_data(_, "test","test","test").,(3)ユーザー定義単位節 SQL文の定義,select_each,exec_direct,などSQL呼び出しを行う述語で利用するSQL文とそのSQL文が利用するDSNとのリンク、select 時の取得データ型をあらかじめ準備するか動的にアサーションします。,書式,sql_statement(SQL識別子,出力定義リスト,SQL文リスト).,SQL識別子,select_each,exec_direct,などSQL呼び出しを行う述語に指定され、SQL文を一意に選択するための識別子です。,出力定義リスト,select呼び出しのみ意味を持ち、select アイテムの取得型をその順に記述します。,RDB上の定義と異なってもいい場合もあります。,(DB:integer => Prolog:atom),<出力データ型の定義>,char/文字数:結果は文字数以内の長さのアトム,date:結果は年月日の数値3要素のリスト,long:結果はinteger,double:結果はfloat,timestamp:結果は年月日時分秒シーケンス番号の数値7要素のリスト,SQL文(リスト):,リストの要素を平坦結合したものがSQL文としてRDBへ渡されます。,要素は文字列リスト、アトム、数値、date型年月日表現リスト(<例> [2006,12,31] )および変数で、変数は出現順に呼び出し元から与えられる入力値リストで埋められます。,SQL識別子 出力定義リスト SQL文,sql_statement(create,[],["create table 山岳テーブル ",,"( 山名 char(16) primary key, 地域 char(10) ,標高 integer,"," 緯度 integer, 経度 integer, 地図 char(16) )"]).,sql_statement(insert,[],["insert into 山岳テーブル",,% 変数は呼び出し時に値を与えます" values ( '",_,"','",_,"',",_,",",_,",",_,",'",_,"')"]).,sql_statement(select,[char/20,long],["select 山名,標高 from 山岳テーブル ",_,_]).,sql_statement(select2,[char/20,char/20,long,long,long,char/20],["select * from 山岳テーブル where ",_]).,(4)SQL文の実行, select_each/3 ,SQL文を実行する。非決定性述語。バックトラックにより次解を返す。,?-select_each(-取得結果リスト,+SQL識別子,+SQL文の変数充当データリスト).,-取得結果リスト:SERECT文の場合、取得データがリストで返る,+SQL識別子: sql_statement/3 を特定する識別子,+SQL文の変数充当データリスト:SQL文中の変数に充当するデータ, exec_direct/2 ,結果取得をともなわないSQL文(insert,delete,dorp など)を実行する,?-exec_direct(+SQL識別子,+SQL文の変数充当データリスト)., exec_directs/3 ,結果取得をともなわないSQL文(insert,delete)を複数の充当値で実行する,?-exec_directs(+SQL識別子, 変数充当データリストのリスト,-エラーリスト).,-エラーリスト:実行エラーとなった変数充当データリストのリスト, is_null/1 ,引数である該当取得データがnullの時に成功する, sql_cancels/1 ,指定SQL識別子の問い合わせをキャンセルする, odbc_close/0 ,現在接続されている全てのODBCコネクションをクローズする。,★なお、前記の述語の部品を構成する次のものもPublicとなっている。SQL処理の間に別の処理をはさむ必要があったときなどに利用できる。仕様詳細はソースコード(odbc_prolog.pl)参照のこと。, odbc_open/3  , select_each/4 , select_each/6 , fetch_one/4 , exec_directs_pre/4 , exec_directs_post/2 , exec_directs_main/4 ,★また、ODBCとの最下層のやり取りは、Cソースコンパイルド組込述語による。これらの仕様詳細はソースコード(odbc.c)を参照のこと。ユーザ独自のSQL操作系を構成できる。,(5)実行例,1)ODBC拡張機能を取り込みます,| ?- dlib_require(odbc).yes,2)テーブルの生成,テーブルが生成されます。,?- exec_direct(create,[]).,yes,3)データのインサート,データがインサートされます, insert_data/1 はフィールドに埋めるデータ並びのリストの単位節です。,?-insert_data(X),exec_direct(insert,X),fail.,No, なお、これは次の方法でもよい。,?-bagof(X,insert_data(X),L),exec_directs(insert,L,Err).,4)データの条件なし取得   ,全件なので元SQL文の変数部分に空を渡します。,?- select_each(X,select,["",""]).,X= [富士山,3776];,X= [北岳,3192],5)データの条件つき取得,?- select_each(X,select,["where 標高 < ",3000]).,X= [剣岳,2998];,X= [水晶岳,2986],% インサートデータ,%  山名 地域  標高  緯度 経度 地図,insert_data([富士山, 富士周辺,3776,352127,1384350,富士山]).,insert_data([北岳, 南ア北部,3192,354017,1381431,仙丈ヶ岳]).,:,insert_data([鷲羽岳, 北ア北部,2924,362400,1373630,三ツ俣蓮岳]).,insert_data([大天井岳, 北ア北部,2922,362143,1374215,槍ヶ岳])."}); htmllist.push({"file":"manuals/manuals/manual_odbc.html#odbc_2","title":"9-10-2.AZ-Prolog用のODBCインターフェース基層述語","text":"9-10-2.AZ-Prolog用のODBCインターフェース基層述語,(1)概要,1.ODBC 64ビットバージョン,Windows 7(64bit),Microsoft Access 2013(64bit),ODBCドライバ(MSAccess)14.00.7010.1000,ODBCドライバ(SQL Server)6.01.7601.17514,ODBCドライバ(SQL Server Native Client)2011.110.3000,Windows 7(64bit) MS Access 2013(64bit),Windows 7(64bit) SQLServer 2012 ExpressEdition(64bit),2.ODBC 32ビットバージョン,Windows 2000,Microsoft SQL Server 2000,ODBCドライバマネージャ 3.520.6526.0,ODBCドライバ(SQL Server) 2000.80.194.00,Windows 7(32bit) MS Access,Windows XP(32bit) MS Access,上記の構成で動作確認を行っています。,ODBC自体については、ODBCに関する文献、本マニュアル等を参照してください。,ソース:odbc.c,(2)ODBCインターフェース,1)定数,ODBCで使用されるシンボルの内、以下のものが同じ名前で,アトムとして組み込まれている。,(但し、全て小文字に置き換えている),NULLハンドル値,sql_null_handle,戻り値(RV),sql_succeeded,sql_no_data,sql_error,sql_invalid_handle,sql_still_executing,sql_need_data,Cデータ型(CT),sql_c_char,sql_c_long,sql_c_double,sql_c_date,sql_c_timestamp,SQLデータ型(SQLT),sql_char,sql_varchar,sql_longvarchar,sql_decimal,sql_numeric,sql_smallint,sql_integer,sql_real,sql_float,sql_double,sql_bit,sql_tinyint,sql_bigint,sql_binary,sql_varbinary,sql_datetime,sql_type_time,sql_type_timestamp,ハンドル型(HT),sql_handle_env,sql_handle_dbc,sql_handle_stmt,入出力タイプ(IOT),sql_param_input,sql_param_output,sql_param_input_output,トランザクション(TT),sql_commit,sql_rollback,2)述語,以下の述語が組み込まれている。,2.1) 補助述語,これらはODBC関数には対応するものが存在しないが、Prologで使用するために,必要なので用意されている。, sql_free_param/1 , sql_free_params/1 , sql_get_param/2 , sql_set_param/2 , sql_select_assert/4 , sql_select_assert_limit/1 , sql_error_info/1 ,2.2) ODBC述語,同名のODBC関数(但しアンダースコアで区切られている)と同じ機能を持つ。,(<例>ODBC関数 SQLConnect() --> 述語 sql_connect),sql_alloc_handle/3 ,sql_alloc_env/1 ,sql_alloc_connect/2 ,sql_bind_col/5 ,sql_bind_parameter/9 ,sql_connect/4 ,sql_disconnect/1 ,sql_free_handle/2 ,sql_free_connect/1 ,sql_exec_direct/2 ,sql_execute/1 ,sql_end_tran/3 ,sql_fetch/2 ,sql_prepare/2 ,sql_row_count/2 ,2.3) 補助述語詳細,補助関数には、パラメタに関する操作を行う述語と、,検索と検索結果のassertを一度に行うための述語がある。,パラメタとは、SQL文に関連付けられて、値の入出力のために存在するもので、,ODBC関数で使用される。(具体的には、sql_bind_col/5, sql_bind_parameter/9,の中でパラメタが生成される。),パラメタは、パラメタの生成時点で指定されたCデータ型(CT)をもつ。,以下の説明の中の引数の表記で、+は入力、-は出力を表す。,sql_free_param(+Param),指定した一個のパラメタの領域を開放する。,そのパラメタは使用できなくなる。,<例> sql_free_param(X).,sql_free_params(+ParamsList),指定したリストの全ての要素のパラメタの領域を開放する。,<例> sql_free_params([P1, P2, P3]).,sql_get_param(+Param, -Value),指定したパラメタの値を取得する。,<例> sql_get_param(P, V). %% ==> V = 10.6,パラメタがsql_c_char型のときは値はアトムになる。,sql_c_date型のときは、三個の要素をもったリスト([Year, Month, Day])になる。,sql_c_timestamp型のときは、七個の要素をもったリストになる。,([Year, Month, Day, Hour, Minute, Second, Fraction]),sql_set_param(+Param, +Value),指定したパラメタの値をセットする。,<例> sql_set_param(P, 200).,値の型については、sql_get_param/2の説明を参照。,但し、パラメタがsql_c_char型のときには、アトムではなく、,文字列(AZ-Prologでは整数のリスト)で指定しても良い。,sql_select_assert(+Stmt, +ColTypeList, +ColLengthList, +PredName),指定したSQL文ハンドル(Stmt)を実行し、その検索結果の全ての行に対して、,述語名がPredNameの節をassertする。,ColTypeListはStmtにバインドするカラムの型のリストであり、ColLengthListは,カラムのサイズのリストである。(sql_bind_col/5参照),<例> sql_select_assert(Stmt,,[sql_c_char, sql_c_char, sql_c_timestamp, sql_c_long],,[4, 20, _, _], sales).,%% ==>,sales('6380', '6871', [1994,9,14,0,0,0,0], 5).,sales('7131', 'D4482', [2001,3,11,0,0,0,0], 20).,sql_select_assert_limit(+LimitNum),sql_select_assert/4でassertする個数をLimitNum個に制限する。,無制限にするときは、LimitNumに-1を指定する。,(デフォルトは無制限),<例> sql_select_assert_limit(30).,sql_error_info(-Info),ODBC関数の実行が正常終了しなかったとき、,そのエラーに関する情報文字列をアトムで返す。,<例> sql_error_info(S). %% ==> S = 'SQLBindCol: ......',どういう訳か、SQLGetDiagRec()がまともな情報を返してくれることが,滅多にないので、返される文字列の内の先頭の関数名以外は滅茶苦茶な,ことが多いが、私にはどうすることもできない。,2.4) ODBC述語詳細,ODBC関数自体の機能については、ODBCに関する文献、マニュアルを参照。,sql_alloc_handle(+HT, +InHandle, -OutHandle),指定したハンドル型(HT)のハンドルを生成して返す。,InHandleはハンドル値またはsql_null_handleアトムを指定する。,<例> sql_alloc_handle(sql_handle_stmt, DBC, Stmt).,sql_alloc_env(-Env),環境ハンドルを生成する。,<例> sql_alloc_env(Env).,sql_alloc_connect(+EnvHandle, -DBCHandle),DB接続ハンドルを生成する。,最初の引数で環境ハンドルを指定する。,<例> sql_alloc_connect(Env, DBC).,sql_bind_col(+Stmt, +ColNum, +CT, -Param, +Size),パラメタを生成して、指定したSQL文ハンドルの指定した番号のカラムに,バインドする。生成されたパラメタがParam引数にセットされる。,ColNumはカラム番号(1から始まる)。,CTはパラメタのCデータ型アトム。,Sizeはsql_c_char型のときにだけ意味がある。他の場合は不定値でもよい。,<例> sql_bind_col(Stmt, 2, sql_c_char, OrderNum, 20).,sql_bind_parameter(+Stmt, +Num, +IOT, +CT, +SQLT, +ColSize, +DecimalDigit,,-Param, +Size),パラメタを生成して、指定したSQL文ハンドルの指定した番号のパラメタとして,バインドする。生成されたパラメタがParam引数にセットされる。,Numはパラメタの番号(1から始まる)。,CTはパラメタのCデータ型アトム。,SQLTはSQLデータ型アトム。,Sizeはsql_c_char型のときにだけ意味がある。他の場合は不定値でもよい。,ColSize, DecimalDigitについては、ODBC関数のSQLBindParameter()を参照。,<例> sql_bind_parameter(Stmt, 1, sql_param_input, sql_c_date, sql_char,,0, 0, ParamOrdDate, 0).,sql_connect(+DBCHandle, +DSN, +UserName, +Password),指定したDB接続ハンドルで、データーベースに接続する。,DSN, UserName, Passwordはアトムまたは文字列で指定する。,<例> sql_connect(DBC, 'AnyDSN', 'yamamoto', 'aaaaaaaaaaaaaa').,sql_disconnect(+DBCHandle),指定したDB接続ハンドルの接続を切る。,<例> sql_disconnect(DBC).,sql_free_handle(+HT, +Handle),指定したハンドルを開放する。,<例> sql_free_handle(sql_handle_env, Env).,sql_free_connect(+DBCHandle),指定したDB接続ハンドルを開放する。,<例> sql_free_connect(DBC).,sql_exec_direct(+Stmt, +SQLString),指定したSQL文ハンドルで、指定したSQL文を直接実行する。,SQLStringは、アトムか文字列で指定する。,<例> sql_exec_direct(Stmt, "delete sales where ord_date = '2002-04-23'").,sql_execute(+Stmt),指定したSQL文ハンドルを実行する。,<例> sql_execute(Stmt).,sql_end_tran(+HT, +Handle, +CompletionType),指定したハンドルで、指定したタイプでトランザクションを終了する。,CompletionTypeは、sql_commitかsql_rollbackのどちらか。,<例> sql_end_tran(sql_handle_dbc, DBC, sql_commit).,デフォルトで自動コミットモードになっているのであれば、,これを実行しても意味がない。,sql_fetch(+Stmt, -Result),実行されたSQL文ハンドルの一行分の結果を取得する。,結果の値は、sql_bind_colされたパラメタにセットされる。,Resultには、戻り値(RV)として定義されたアトムのどれかが返される。,<例> sql_fetch(Stmt, Result). %% ==> Result = sql_succeeded,sql_prepare(+Stmt, +SQLString),指定したSQL文ハンドルで、指定したSQL文の実行を準備する。,SQLStringは、アトムか文字列で指定する。,<例> sql_prepare(Stmt, "select stor_id, ord_num, qty from sales where ord_date = ?").,sql_row_count(+Stmt, -Count),指定したSQL文ハンドルの実行結果として影響を受けた行数を返す。,(INSERT, UPDATEのときのみ),<例> sql_row_count(Stmt, Row). %% ==> Row = 7"}); htmllist.push({"file":"manuals/manual_ole.html#ole","title":"9-11-1.概要","text":"9-11-1.概要,AZ-Prologは、WindowsのOLEオートメーション機能をサポートしています。,これを利用する事で、AZ-Prolog自体を1つのオブジェクトとしてパッケージ化し、他のWindowsプログラムと連動させる事が出来、開発の効率化を計る事が出来ます。,例えばWindowsのGUI部分は、他のGUI向きの開発言語でコーディングし、複雑なロジックを必要とするプログラム本体は、それを容易に記述出来るAZ-Prologでコーディングし、これらの連携によるシステムを実現させるといったものです。,OLEオートメーション機能の利用例,これにより、各々の言語等のアプリケーションの特徴を最大限に利用する事でシステムの設計・開発が容易になり、またこの柔軟性により、Windows上でのプログラム開発の可能性を拡大させる事が出来ます。,具体的には、AZ-Prologパッケージには、OLEオートメーション機能をサポートした言語によるサンプルプログラムが付属していますので、それを実行してみたりソースファイルに目を通すと、より直感的に理解出来るかと思われますので、そちらも参照してみてください。,この章では、AZ-PrologのOLEオートメーション機能のサポート形式の説明、そして実際のOLEオートメーションサーバの作成例を解説します。,サポート形式の説明は、多少堅苦しく記述されていますが、作成例を読みながらもう一度参照し直すと理解しやすいかと思います。"}); htmllist.push({"file":"manuals/manual_ole.html#ole_2","title":"9-11-2.OLEオートメーション機能のサポート形式","text":"9-11-2.OLEオートメーション機能のサポート形式,(1)automation/3述語,OLEオートメーションを使用する場合は、まずプログラムのクラス名、及びCLSIDを決める必要があります。,クラス名はアプリケーションをクライアントから呼び出すときに使用する名前、CLSIDはウインドウズオブジェクト(複合ドキュメントのオブジェクト、オートメーションオブジェクト等)をWindowsのレジストリデータベースに登録する時に指定する識別番号です。,CLSIDはアプリケーション毎に異なる値を持つ必要があり、逆に同一アプリケーションのCLSIDは(実行するコンピュータが異なっても、また、バージョンが異なっても同一アプリケーションといえる限りは)同じものである必要があります。,この登録、及びOLEオートメーションサーバの実行を行う為の述語「automation/3」が用意されています。,automation(CLSID, ProgID, EXEname),実際の動作はコマンドライン引数によって以下のようになります。,①,第一引数が「/Automation」の場合,サーバとしての動作を行います。通常はクライアントのオブジェクト生成要求に従ってOLEによってプログラムが起動された場合がこれにあたります。,クライアントがオブジェクトを破棄することによって述語は成功終了します。,②,第一引数が「/Setup」またはここで述べる他のいずれにも該当しない場合,プログラムの登録を行います。,クライアントが登録名ProgIDのオブジェクトの生成を要求すると、次のコマンドラインでサーバが起動されるようになります。,“<EXEname> /Automation -Embedded <Args>”,ここでは述語の引数、 は登録時のコマンドライン引数から第一引数の「/Setup」を除いたものです。,登録終了時、第一引数が'/Setup'でない場合、登録完了を知らせるメッセージが表示されます。,③,第一引数が「/Uninstall」または「/SilentUninstall」の場合,登録の削除を行います。,削除終了時、第一引数が「/Uninstal」の場合、削除完了を知らせるメッセージが表示されます。,②または③の場合、「/Setup」等に続いて「/Private」または「/Public」を指定することでプログラムの登録が現在ログインしているユーザーだけに有効なものかシステム全体に有効なものにするかを指定できます。,この指定を省略するとシステム全体に有効なものになります。,システム全体に有効な登録はUACによって制限されるので、一時的にUACを無効にするなどの対策が必要になります。,従って開発中のものを登録する場合等は「/Private」で登録するのがよいでしょう。,CLSID,プログラム固有のインターフェースIDの文字列表現,ProgID,トップレベルオブジェクト(次項参照)の公開名(クラス名),EXEname,実行ファイル名及びサーバ起動時「/Automation -Embedded」の前に必要なコマンドライン引数,(2)外部インターフェース,クライアントが最初に取得するオブジェクトをトップレベルオブジェクトと呼びます。,これはインタプリタのトップレベルに相当する物です。トップレベルオブジェクトは以下のメソッドを持ちます。,メソッドCallFormula(Formula,Term),式の実行を開始します。,引数Formulaは実行すべき式、TermはFormulaの実行が成功した時結果表示オブジェクトを通して取得すべき項です。,戻り値はオブジェクトです。,CallFormulaの戻り値として得られるオブジェクトを結果表示オブジェクトと呼びます。,結果表示オブジェクトは以下のプロパティ、及びメソッドを持ちます。,プロパティ Status,Formula実行の現在の状況を示します。,"Succ",成功している。,"Fail",失敗している。,"Error",エラーが起こった。,プロパティ Value (デフォルトプロパティ),Status="Succ"の時、Termの現在の値を示します。,Status="Error"の時、エラー番号を示します。,メソッドGetAlternative,結果表示をフェイルさせ、別解を探索します。,(3)例外,Prolog内部で起こったエラーは常に結果表示オブジェクトのStatusプロパティを通して報告されます。以下の状況ではOLEのエラーとなり例外コードが返されます。,例外コード1001,結果表示オブジェクトの参照が解除されないままトップレベルオブジェクトが使用された。,例外コード1002,Status="Fail"の時にValueプロパティを取得しようとした。,例外コード1003,Status="Succ"以外の時にGetAlternativeメソッドを実行しようとした。"}); htmllist.push({"file":"manuals/manual_ole.html#ole_3","title":"9-11-3.OLEオートメーションサーバの作成","text":"9-11-3.OLEオートメーションサーバの作成,(1)はじめに,ここではクライアントプログラムの例はVBのコーディングで示すことにします。,(2)プログラム本体の記述,プログラム本体の記述に関しては特別な事は何もありません。普通に述語を作成してコンソール上でデバッグします。,(3)オートメーションサーバとして動かす,A,AZSERV.EXEに読み込ませて使う。,B,インタプリタを使用する。,C,コンパイルする。,の3種類の方法が考えられます。,以下、それぞれの方法について説明します。,A.AZSERV.EXEに読み込ませる,この場合にはPrologでのプログラムは本体だけで他には必要ありません。,呼び出し側のプログラムで以下のようにして使用します。,<VBでのコーディング例 (VB2010の場合)>,Public Class Form1,Dim objToplevel As Object,Dim objQuery As Object,Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load,objToplevel = CreateObject("Prolog.Toplevel"),objQuery = objToplevel.CallFormula("consult('C:¥programs¥myapp.pl') ", "_"),System.Runtime.InteropServices.Marshal.ReleaseComObject(objQuery),End Sub,End Class,このプロシージャを実行した後はToplevelオブジェクトを使用して述語呼び出しを行うことができます。,B.インタプリタを使用する,この場合はまずプログラムのクラス名及びCLSIDを決める必要があります。,クラス名はアプリケーションをクライアントから呼び出すときに使用する名前、CLSIDはウインドウズオブジェクト(複合ドキュメントのオブジェクト、オートメーションオブジェクト等)をWindowsのレジストリデータベースに登録する時に指定する識別番号です。,CLSIDはアプリケーション毎に異なる値を持つ必要があり、逆に同一アプリケーションのCLSIDは(実行するコンピュータが異なっても、また、バージョンが異なっても同一アプリケーションといえる限りは)同じものである必要があります。,新規アプリケーションのCLSIDを生成するには通常はWindows SDKやVisual C++などの開発ツールに付属するGUIDGEN.EXEというプログラムを使用します。,GUIDGENの使用方法はそちらのマニュアルを参照して下さい。,NEWGUID.EXEはコマンドラインから実行すると新しいCLSIDを生成して標準出力に書き出します。,リダイレクトしてファイルに埋めこむ等の方法で使用して下さい。,ここでは仮にプログラム本体が「C:¥programs¥myapp.pl」にあるとし、クラス名を「MyApp.Toplevel」、CLSIDを「{12B061D0-DEAC-11CE-A641-0000F4CA088B}」として説明します。(このCLSIDはこの原稿を書いている時にNEWGUID.EXEを使用して生成した値です。),プログラム初期化コマンドファイルとして「C:¥programs¥myapp.ini」を作成し、以下の内容を書き込みます。(もちろんmyapp.plの末尾に追加しても構わないですが),myapp.iniの内容,:-consult('C:¥programs¥myapp.pl').,:-automation(,'{12B061D0-DEAC-11CE-A641-0000F4CA088B}',,'MyApp.Toplevel',,'C:¥azprolog¥bin¥prolog.exe -s C:¥programs¥myapp.ini -nologo -p').,:-halt.,Prologの起動オプション-nologoはインタプリタ起動時のメッセージ表示を抑止します。,Prolog(及びコンパイルオプション「/i」あるいは「/curses」をつけてコンパイルしたスタンドアロンPrologアプリケーション)は最初にコンソール入出力を行ったときはじめてコンソールウィンドウを表示するようになっています。,通常は起動メッセージの表示のために起動と同時にコンソールウィンドウが表示されますが、-nologoオプションをつけて起動すればプログラムが入出力を行わない限り(あるいはトップレベルのプロンプトを表示するまで)コンソールウィンドウは表示されません。,プログラムに絶対パスを埋めこむことが不都合なら起動パラメータからディレクトリ名を得る等の方法が考えられます。これはAZSERV.EXEが行っている方法なのでAZSERV.EXEのソース(AZ-PrologインストールディレクトリのSYSTEMサブディレクトリにあります。)を参照してください。,他にもインストール毎に異なる情報をサーバプログラムに伝えるために起動パラメータを使用できます。,初期化コマンドファイルを作成したらプログラムをウィンドウズのレジストリに登録します。,これは作成したプログラムを単に実行することで行われます。,C:¥programs>prolog -s myapp.ini -nologo,これで登録が完了した旨のメッセージボックスが表示され、MyApp.Toplevelという名前でプログラムが呼び出せるようになります。,セットアッププログラムから実行する場合などメッセージボックスが邪魔な場合はプログラムパラメータのはじめに「/Setup」を指定します。,C:¥programs>prolog -s myapp.ini -nologo -p /Setup /Private,こうすると登録は同様に行われますが、メッセージは何も表示せず登録完了後直ちに終了します。,また、「/Private」を指定しているので登録を実行したユーザーのみに有効な登録になります。,クライアントアプリケーションはクラス名MyApp.Toplevelのオブジェクトを取得するだけでプログラムを呼び出すことができます。,<VBでのコーディング例(VB2010の場合)>,Public Class Form1,Dim objToplevel As Object,Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load,objToplevel = CreateObject("MyApp.Toplevel"),End Sub,End Class,あとはAZSERV.EXEを使用する場合と同様です。,C.コンパイルする,コンパイルする場合もインタプリタで実行する場合とほぼ同じ手順になります。,以下の内容をプログラムに挿入するか一緒にコンパイルしてリンクします。,(もちろんクライアントから呼び出される述語はpublicにします。),top_level:-,automation(,'{12B061D0-DEAC-11CE-A641-0000F4CA088B}',,'MyApp.Toplevel',,'C:¥azprolog¥bin¥myapp.exe -p').,プログラムをコンパイルしmyapp.exeを作成し、それを単に実行して登録します。クライアント側はインタプリタで実行するばあいと全く同じプログラムで使用できます。"}); htmllist.push({"file":"manuals/manual_ole.html#ole_4","title":"9-11-4.OLEオートメーション関連述語一覧","text":"9-11-4.OLEオートメーション関連述語一覧, ole_initialize/0 ,OLEオートメーションシステムの初期化, ole_uninitialize/0 ,OLEオートメーションシステムの終了処理, ole_create_object/2 ,オートメーションオブジェクトの取得, ole_release_object/1,オートメーションオブジェクトの使用終了, ole_call_method/5 ,メソッドの呼び出し, ole_get_property/5 ,オートメーションオブジェクトのプロパティの値を取得, ole_put_property/4 ,オートメーションオブジェクトのプロパティの値を設定"}); htmllist.push({"file":"manuals/manual_azedit.html","title":"9-12-1.概要","text":"9-12-1.概要,AZ-Prolog インタプリタはスクリーンエディタ (AzEdit) を内蔵しており、それを使って効率良くプログラムの修正および追加を行うことができます。,このエディタとインタプリタは密接な関係にあります。例えば、エディタコマンドにより、エディタバッファ(テキストを格納する領域)からファイルを介さずに直接、ヒープ領域(インタプリタのプログラム領域)に転送(コンサルトまたはリコンサルト)できます。しかも、シンタックスチェックをしながら転送しますので、転送中に構文エラーが発見されると、カーソルが移動してその箇所を知らせます。,また、このエディタ自身もPrologで記述されていますので、Prologの基礎知識があれば、そのプログラムを変更することで、キー割り当ての変更を初め、機能の追加・変更も自由にできます。,提供されたインタプリタにはコンパイルされたAzEditが拡張ライブラリとして付属していますので、読み込んでご使用いただけます。,?- dlib_require(azedit). ,新しくインタプリタを生成する場合にはazedit.plをコンパイルしなおして付加するか、コンサルトして使用することが可能です。画面制御を伴うため、コンパイルする際はコンパイルオプション「/curses」または「/i (/dcursesを併用しない)」が必須となります。,本章ではAzEditの使い方と、機能拡張の方法を説明しています。,以下ここの説明で使う用語の定義をしておきます。,【エディタバッファ】,編集するテキストを格納するためのメモリ上の領域です。,AZ-Prolog ではこのバッファを最大8個まで確保できます。,なお、以下では単に、バッファと呼ぶこともあります。,また、漢字などの2バイト文字の扱いは書き込み時の漢字モードによって決定されます。,(漢字モードが「on」の場合は2バイトをまとめて1文字として扱い「off」の場合は1バイトずつに分けて2文字として扱います),【バッファ番号】,バッファを識別するため、各バッファに付けられた番号です。,【現在のバッファ番号】,現在(述語を実行した時点)の操作対象となっているバッファの番号。,この現在のバッファ番号は「^C」コマンドにて変更(切り替え)できます。,なお、インタプリタ立ち上げ直後のデフォルト値は0です。,【キルバッファ】,「^W」「^K」「ESC D」コマンドでエディタバッファ内の文字列を削除した場合にその文字列が一時的にこのキルバッファに格納される仕組になっています。,キルバッファに格納された文字列は「^Y」コマンドによって任意の位置(現在のドット位置の次)に挿入することができ、これによって文字列の移動やコピーができます。,なお、このキルバッファは1つだけで各エディタバッファで共有します。,これにより、各エディタバッファ間でも文字列の移動やコピーができます。,【ドット】,通常は画面のカーソルがある位置がドット位置です。,バッファ中のポインタの一種で、このドットが指し示す位置に対して文字列の挿入・削除などの編集が行われます。,【マーク】,ドットと同じくバッファ中のポインタの一種で、このマーク位置へのジャンプや、このマークとドット間の文字に対して削除、キルバッファへのコピー、ヒープ領域へのコンサルトなどの操作を行うことができます。,なお、このマークは画面には表示されません。,【位置】,バッファの先頭からの文字数。,【文字数】,英数字などの1バイト文字は無条件で1文字と数えますが、漢字などの2バイト文字は書き込み時の漢字モードによって決定されます。,書き込み時の漢字モードが「on」だった場合は1文字として数え、「off」だった場合は1バイトずつに分けて2文字として数えます。,【NL】,改行コード。,【文字コード】,英数字などの1バイト文字のキャラクタコード、漢字などの2バイト文字の漢字コードを総称して「文字コード」と呼んでいます。,【画面】,コンソール画面、またはウィンドウシステムでは一つのウィンドウを指します。,【終端行】,画面中、エディタで使用している部分下端の次の行です。,「AZ-Prolog Editer (Version ….)*」と表示されます。,現在のバッファ番号が * のところに表示されます。,【前方】,バッファの最後に向う方向。(画面の下方向),【後方】,バッファの先頭に向う方向。(画面の上方向),【下方】,画面の下方向。バッファの最後に向う方向。前方。,【上方】,画面の上方向。バッファの先頭に向う方向。後方。,【直後】,すぐ前方。,【直前】,すぐ後方。"}); htmllist.push({"file":"manuals/manual_azedit.html#azedit_2","title":"9-12-2.AzEditの使い方","text":"9-12-2.AzEditの使い方,この節では AzEditでテキストを編集するために必要なコマンドを説明します。,AzEdit のコマンドは、コントロールキーあるいはエスケープキーを押すことにより実行されます。,なお「CTRL-F」(以下、「^F」と表現することもあります)は「コントロールキーを押しながらFを押すこと」を示すのはこれまでの章と同じです。,Windowsなどの一部OSでは、ESCキーが取得されないものもあり、このときはESCキーの代わりに「CTRL-[」で代用できます。コントロールキーを押しながら“[“キーを押します。,(1)AzEditの起動,AzEditのプログラムを dlib_require(azedit) で読み込むと、次の3種類の方法よってエディタを起動することができます。,a)|?-edit.,b)|?-edit(述語名).,c)|?-editall.,a)で起動した場合,現在のエディタバッファの状態でAzEditが起動されます。,b)で起動した場合,エディタバッファを一旦空にして、ヒープ領域に定義されている述語の中から『述語名』で指定された述語のテキストをバッファエディタに転送後エディタを起動します。,また、『述語名』をlistingの場合と同じように『述語名/引数の数』、あるいは『述語名』と『述語名/引数の数』からなるリストを指定することもできます。,c)で起動した場合,エディタバッファを一旦空にして、現在ヒープ領域定義されている全ての述語をエディタバッファに転送後エディタを起動します。,★インタプリタ立ち上げ後最初の起動,インタプリタ立ち上げ後最初にAzEditが起動されると、画面をクリアして,EditBuffersize(char):,と表示されます。,編集するテキストの文字数を入力して下さい。,(入力する値が、バイト数ではなく文字数であることに注意して下さい),すると、画面のほぼ中央に,AZPrologEditer(Version1.0)-0,と表示されて、カーソルが画面の左上にあるはずです。,この表示された文字列はAzEditが画面上で使用する下端を示しています。,この文字列の最後の「-0」は現在のバッファ番号を表しています。,インタプリタ立ち上げ後最初にAzEditが起動されると必ず「0」となります。,★AzEditの再起動,一旦AzEditを終了した後に再び起動したときは、画面の上から数行をクリアしてそこにテキストの一部を表示して、その下端に,AZPrologEditer(Version1.0)?0,が表示されます。,そして、カーソルは現在のドット位置を示します。,これ以降テキストが変更されるとそれと同時に画面も変化し、常に編集しているテキストの状態を画面に表示します。,(2)カーソルの移動,CTRL-F,カーソルを一文字前に移動(Forwardcharacter),CTRL-B,カーソルを一文字後ろに移動(Backwardcharacter),CTRL-N,カーソルを一行下に移動(Nextline),CTRL-P,カーソルを一行上に移動(Previousline),ESC-F,カーソルを現在の単語の次に移動 (Forwardword),ESC-B,カーソルを一つ前の単語の先頭に移動(Backwardword),CTRL-A,カーソルを次の行の先頭に移動,CTRL-E,カーソルを次の行の最後に移動(Endofline),CTRL-V,次の画面を表示(Viewthenextscreen),CTRL-Z,前の画面を表示,ESC-,カーソルをテキストの先頭に移動,WSC->,カーソルをテキストの最後に移動,CTRL-X CTRL-X,カーソルとマークの交換(Exchange),ESC-Space,カーソルの位置にマークを付ける,CTRL-L,カーソルを中心に画面を再配置,(※カーソル移動コマンドは、英語を連想すると覚えやすいでしょう。),AzEditでは、削除、挿入などのテキストの修正は全て現在表示されているカーソルの前後おいて行われます。,そのため、まずカーソルを所定の位置へ移動させる必要があります。,カーソル移動の基本的なコマンドとして、「CTRL-F」「CTRL-B」「CTRL-P」「CTRL-N」があります。,「CTRL-F」はカーソルを一文字前(テキストの最後に近づく方向)に進め、「CTRL-B」は逆にカーソルを一文字後ろ(テキストの先頭に近づく方向)に戻します。,また、「CTRL-P」は上、「CTRL-N」は下の行にカーソルをそれぞれ移動させます。,カーソルが行の最後にある場合にCTRL-Fを行うと、カーソルは次の行の先頭に移動します。,逆に、カーソルが行の先頭にある場合にCTRL-Bを行うと、前の行の最後に移動します。,このようにAzEditではテキストは一連のつながった文字の列として取り扱われ、行と行の区切りにはNL(NewLine)が文字として入れられています。,現在画面に表示されている外側にカーソルを移動させようとすると、自動的に前あるいは後ろの画面が表示されます。,例えば、カーソルが画面に表示されている最後の行にあるときに「CTRL-N」を行うと、次の画面が表示されます。,前の画面と新しい画面にはつながりを持たせるために数行のオーバーラップの行があります。,(オーバーラップの行数はそのときにAzEditが使用している行数の約1/4です。),「CTRL-F」「CTRL-B」は一文字ごとにカーソルを前後に動かしましたが、単語単位で動かすこともできます。「ESC-F」は現在の単語の次の位置にカーソルを移動させ、「ESC-B」は一つ前の単語の先頭に移動させます(単語とは、一連のカナ漢字あるいは英数字の列のことです)。,現在カーソルのある行の先頭への移動は「CTRL-A」、最後へは「CTRL-E」で行えます。,カーソルが既に行の先頭あるいは最後にある場合に「CTRL-A」「CTRL-E」をそれぞれ行ってもカーソルは移動しません。,「CTRL-V」「CTRL-Z」は画面単位に移動させます。,「CTRL-V」は次の画面を、「CTRL-Z」は前の画面を表示します。,さらに、テキストの先頭には「ESC-でカーソルをそれぞれ移動させることができます。,このとき、誤ってこれらのコマンドを使用した場合にすぐにもとの位置に戻せるように、コマンドを実行するまえのカーソルの位置にマークが付けられます。,マークの付けられた位置への移動は「CTRL-X CTRL-X (CTRL-Xを2度続けて打つ)」によって行えます。,実際には、「CTRL-X CTRL-X」は現在のカーソルの位置とマークされた位置を交換します。,つまり、カーソルはマークされた位置に移動し、前にカーソルのあった位置に新しいマークが付けられます。,また、「ESC-Space(エスケープキーを押してからスペースキーを押す)」現在のカーソルのある位置にマークを付けることもできます。,最後に、カーソルの移動ではありませんが、現在カーソルのある位置を中心としてテキストの前後を見たい場合がよくあります。,こんなときは「CTRL-L」で現在カーソルのある行を画面の中心として、その前後のテキストを再表示します。,(3)挿入と削除,Return,NLをカーソルの前に挿入,CTRL-O,NLをカーソルの位置に挿入(Openline),Tab,タブをカーソルの前に挿入,CTRL-Q,特殊文字の挿入(Quotedinsert),CTRL-D,カーソル位置の文字を削除(Deletecharacter),BS,CTRL-H,カーソルの前の文字を削除(BackSpace),ESC-D,カーソルのある単語を削除(Deleteword),ESC-BS,カーソルの一つ前の単語を削除,CTRL-K,カーソルより右を削除(Killline),CTRL-W,カーソルとマークの間を削除(Killregion),CTRL-Y,ESC-D,CTRL-K,CTRL-Wで削除した,テキストをカーソルの前に挿入(Yank),★挿入,AzEditはいわゆるインサートモードとなっていますので、文字あるいは文字の列を挿入したい場合には、単にその文字あるいは文字列を打ちます。,コントロールキーあるいはエスケープキーを伴わずに打たれた文字は全て現在カーソルのある位置の前に挿入されます。(オーバーライト(上書き)モードではありません。AzEditを改造すればオーバーライトモードを作ることもできます),例えば「append」と打てば、カーソルのあった位置以降に「append」が挿入され、カーソルは「append」の次の位置となります。,文字の挿入によってその行が画面の横の長さを超えた場合には、画面右端に「!」が表示され、その行と次の行が続いていることを示します。,一つの長い行を途中で切って二つの行にしたいときには、カーソルを切りたい位置に移動してリターンキーを押します。NLが挿入されてカーソルより右の文字が新しい行になります。,また、「CTRL-O」は、カーソルの位置にNLを挿入し、カーソルは移動しません。,また、タブキーを押すと「CTRL-I」がテキストに挿入され、画面にはカーソルから次のタブストップまでの分の空白が表示されます。(タブストップは、1カラム目、9カラム目、7カラム目というように8カラム毎に設定されています),コントロールキーあるいはエスケープキーは、通常、コマンドとして取り扱われるためにテキストには挿入されません。,まず「CTRL-Q」を打ってから目的のキーを打つとそのコントロールコードが挿入されます。,画面には^が文字の前に付けられて表示されます。(例えば、CTRL-Fは^Fと表示されます),★削除,・一文字単位,バッファのテキストから一文字単位で削除するには、カーソルをその文字の位置に移動させ「CTRL-D」で行います。,また、最後に挿入した文字を削除する場合には、バックスペースキー(BSまたはCTRL-H)で行えます。,即ち、「CTRL-D」はカーソルの位置の文字を削除し、「BS」はカーソルの前の文字を削除します。,既に述べたように、行の区切りも一つの文字ですから、行の最後において「CTRL-D」を行うと、次の行がその行の後ろにつながります。,・単語単位,単語単位での削除は、「ESC-Dと「ESC-BS」で行えます。,それぞれ、「ESC-D」現在カーソルのあるところの単語、「ESC-BS」は一つ前(テキストの先頭より)の単語を削除します。,・行単位,行単位の削除は、「CTRL-K」で行います。「CTRL-K」は、現在のカーソルの位置からその行の最後までを削除、あるいはカーソルが既に行の最後にある場合には、次の行との区切りであるNLを削除します。,例えば、ある行全体を削除したいときには、カーソルをその行の先頭に移動させた後に「CTRL-K」を2回行う必要があります。,・ブロック単位,さらに大きな部分の削除は、「CTRL-W」で行われます。「CTRL-W」は現在のカーソルの位置とマークの付けられた位置の間を削除します。,★復帰挿入,「ESC-D,CTRL-K,CTRL-W」で削除された部分は次の削除コマンドまで(ESC-D,CTRL-K,CTRL-W)テキストとは別のところに取って置かれ「CTRL-Y」によってカーソルの位置に挿入することができます。,「ESC-D」あるいは「CTRL-K」をいくつか連続して使って削除を行った場合には、それら全ては一つのものとして取って置かれC「TRL-Y」で一度に挿入されます。,例えば、間違って「CTRL-K」を押して行が削除された場合には、直ちに「CTRL-Y」を行えば復活させることができます。,★移動・複写,また、これらの機能(削除と復帰)を使うことによりテキストの移動・複写も行うことができます。,まず、「CTRL-K」または「CTRL-W」によって移動させたいテキストを削除し、カーソルを挿入すべき位置に移動した後に、削除したテキストを「CTRL-Y」で復活させます。,復活は何回でも行えますので、テキストの複写が可能です。,(4)検索と置換,CTRL-S 文字列 ESC,前方探索(Search),CTRL-R 文字列,後方探索(Reversesearch),CTRL-S CTRL-S,同じ文字列の前方探索,CTRL-R CTRL-R,同じ文字列の前方探索,ESC-R 文字列1 ESC,文字列2 ESC,文字列1を文字列2に置き換える(Replace),ESC-Q 文字列1 SC,文字列2 ESC,文字列1を文字列2にキーボード,からの指示に従い置き換える(Queryreplace),★検索,CTRL-Sで前向き、CTRL-Rで後ろ向き探索をします。,「CTRL-S」を押すと探索すべき文字列を尋ねてきますので、文字列を入力した後にエスケープキーを押します。,すると、現在のカーソルの位置からテキストの終わりの方に向かって(前向きの探索)入力された文字列と一致する文字列があるかどうかを探索し、もしあった場合には、カーソルはその文字列の次に移動します。,探索が失敗したときには、「FailSearch」と表示し、カーソルは元の位置のままです。,同様に、カーソルの位置からテキストの始めの方に探索したい場合(後ろ向きの探索)には、「CTRL-R」で行います。,さらに、最後に探索に使われた文字列は記憶されていますので、もう一度探索するときには、「CTRL-SCTRL-S」あるいは「CTRL-RCTRL-R」で行えます。,探索において通常は英字の大文字と小文字の区別は行いません。,したがって、例えば、「append」を探索した場合には、「append」だけでなく「APPEND、Append」等も同時に探索されます。,大文字と小文字の区別を行いたいときには、PROLOGにおいて「e_bothcase(_,off)」を実行させます。,★置換,置換には「ESC-R」と「ESC-Q」の2種類のコマンドが用意されています。,ESC-Rでは、探索する文字列とそれを置き換える文字列をエスケープ(画面には「$」で表示されます)で区切って入力すると、現在のカーソルの位置からテキストの最後に向かって探索して見つけた文字列は全て置き換えます。,例えば、「abc」という文字列を「xyz」に置き換える場合は、,ESC R abc ESC xyz ESC,とキーボードから入力します。,すると画面のエコー行に、,Replace$abc$xyz$,と表示されて、現在のカーソル位置から前方にあるすべての「abc」という文字列を「xyz」に置き換えます。,「ESC-」Qは確認付きの置換です。,上のようにESC-Rがカーソル位置から前方の文字列を問答無用に置き換えるのに対し、「ESC-Q」では文字列を見つけるごとに置き換えるか否かを選択できます。,具体的には「ESC-Q」コマンドを入力して、「ESC-R」と同様に検索文字列と置換文字列を画面にその位置をカーソルで指示し、キー入力待ちになります。,ここで置き換えるか、あるいは置き換えずに次の文字列を探すかを指示します。,[スペース]を押下すると置き換えられ、[バックスペース]を押下すると置き換えずに次を探します。,また、[!]を押下するとESC-Rと同じように以後出現する全てを置き換えます。,[その他のキー]を押下すると置き換えを中止します。,(※誤って「CTRL-S」あるいは「CTRL-R」を押してしまった場合には、「CTRL-G」を押せばキャンセルされます。),スペース,置換,バックスペース,次検索,!,未確認全置換,その他のキー,中止,なお、どちらの場合も検索方向は前方のみで、後方に置換することはできません。,(5)ファイル操作,AzEditでは、ディスク上のファイルをバッファに読み込んでそれを編集したり、編集の終了したテキストをファイルにしたりすることができます。,まず、ファイルの読み込みは「CTRL-X CTRL-V」で行います。,CTRL-X CTRL-Vを打ち込むと、ファイル名を尋ねてきますので、編集を行いたいファイルの名前を入力してリターンキーを押します。,コマンド実行以前のテキストを削除して、ファイルからテキストを読み込ませます。その後にテキストの先頭から表示します。,「CTRL-X CTRL-I」はコマンド実行以前のテキストは削除せずに、現在のカーソル位置を先頭としてファイルからテキストを読み込んだ後、カーソルは元の位置に移動させます。,次に、編集の終わったテキストをファイルにセーブしたいときには、「CTRL-X CTRL-W」を行います。,「CTRL-X CTRL-W」コマンドで入力したエコー行にファイル名が表示されますので、それでよければリターンキーだけを押します。,もしファイル名を変更したい場合は、表示されているファイル名をBSキー(バックスペースキー)で削除して、改めてファイルの名前を入力してリターンキーを押します。,ファイル操作コマンド一覧,CTRL-X CTRL-V ファイル名,ファイルをバッファに読み込む(Visitfile),CTRL-X CTRL-I ファイル名,ファイルをバッファに読み込む(Insertfile),CTRL-X CTRL-W ファイル名,テキストをバッファに書き出す(Writefile),(6)プログラム領域への転送,CTRL-X CTRL-S,テキスト全体のreconsult,CTRL-X S,指定領域のreconsult,Prologのプログラムを実行するにはインタプリタのプログラム領域であるヒーヒープ領域に転送する必要があります。,ヒープ領域に転送するにはファイルを介しても可能ですが、AzEditのコマンド「CTRL-X CTRL-S」によって直接「reconsult」することもできます。,「reconsult」ですので既に同じ述語(述語名とアリティが同じ述語)が存在していた場合にはその定義は消去され、AzEditで編集した述語に置き換えられます。,また、「reconsult」中にSyntaxErrorが発生した場合には、そこで「reconsult」が打ち切られカーソルはErrorの発生した位置に移動します。,「CTRL-X CTRL-S」はAzEditの持つすべてのテキストが「reconsult」されますが、テキストの一部だけを「reconsult」することもできます。,「CTRL-X S」では、マークとカーソルの間の領域が「reconsult」されます。,(1)エディタ上のプログラムのコンパイル,AzEditに次のコマンドが追加されています。,また、次のようにすることでエディタ上でのバイトコード・コンパイルが可能です。,(バイトコード・コンパイルについては「コンパイラ」を参照してください。),CTRL-X CTRL-L,バッファ上の全プログラムをコンパイル・ロード,CTRL-X L,マークとカーソル間の述語をコンパイル・ロード,コンパイル結果はファイルとしては残りません。また異なるファイルをエディタからコンパイルしても同一モジュールと見なしますので、最後のもののみ残りますから注意してください。,(7)バッファの領域確保・切り替え・開放,CTRL-C,バッファの切り替え,CTRL-X CTRL-B,バッファの領域を確保,CTRL-X CTRL-C,バッファを切り離し(領域開放),AzEditは同時に複数(最大8個まで)のテキストを扱うことができます。,このバッファは主記憶上(OSの仮想記憶も含む)に確保されます。,個々のバッファの大きさは2の32乗-1文字までです。,ただし、内部の制御情報もバッファ内に置かれますから、格納可能なテキストの大きさはバッファの大きさより11~3割減になります。このため編集するテキストの大きさより大きめに取っておく必要があります。,バッファの操作には「領域確保」「切り替え」「切り離し(領域開放)」があります。,「CTRL-X CTRL-B」コマンドを入力すると最初にAzEditを起動したときと同様にエコー行に、,EditBuffersize(char):,と表示されて、入力待ちになります。希望のバッファの大きさを入れると「領域確保」されます。,AZPrologEditor(Version.....)-*,と表示されて、カーソルが画面の左上にあるはずです。,この文字列の最後の「*」のところに現在のバッファ番号が表示されます。元の最終番号より一つ大きい番号になります。もし、8個のバッファすべてを使っている場合は、,usedallbuffer!!,と表示されてコマンドは無視されます。「CTRL-X CTRL-B」からやり直してください。,バッファを複数個使用している場合に「CTRL-C」で編集するバッファを切り替える(現在のバッファ番号を変更する)ことができます。,「CTRL-C」を押すたびに現在のバッファ番号が一つずつ昇順に切り替わります。最後の番号までいくと「0」に戻ります。,現在、確保されているバッファが一つしかない場合は、切り離しはできません。,nowbufferonly!!,と表示されてコマンドは無視されます。,バッファを切り離すと当然ながらバッファの内容は消されてしまいます。,必要な場合は必ずディスクにセーブしておいてください。,(8)AzEditの終了,CTRL-X CTRL-Z,PROLOGへ戻る,CTRL-X Z,画面の下の部分にスクロール領域を設定してPROLOGへ戻る,AzEditでの編集を止めてPROLOGに戻るには、AzEditが使用していた以後保存された状態でPROLOGが走ります。即ち、画面の上の部分にはAzEditの最終状態を表示したままとなり、画面のスクロールは下の部分で行われます。(CTRL-X Zコマンドは機種により使用できない場合があります。),(9)その他のコマンド,ESC-+,AzEditの使用する行数を一行増やす,ESC--,AzEditの使用する行数を一行減らす,ESC-W,AzEditの使用する行数を最大にする,ESC-U,単語を大文字に変換(Uppercase),ESC-L,単語を小文字に変換(Lowercase),ESC-C,単語を先頭だけ大文字に変換(Capitalize),AzEditは初期設定によって画面の約半分の行数を使用しますが、コマンドによってこれを変更できます。,「ESC-+」は使用する行数を一行増やし、「ESC--」は一行減らします。また、「ESC-W」でいっきに最大にすることもできます。「ESC-U」で、英小文字で書かれた単語を大文字に変換できます。,逆に「ESC-L」で、大文字を小文字に変換することもできます。さらに、先頭の英字だけ大文字にして後は小文字にすることも「ESC-C」で行えます。"}); htmllist.push({"file":"manuals/manual_azedit.html#azedit_3","title":"9-12-3.AzEditのカスタマイズ","text":"9-12-3.AzEditのカスタマイズ,カスタマイズとはユーザ自身が都合や好みに合わせてAzEditのキー割り当ての変更・機能拡張をすることです。,そのために最低限必要な事項をこの節で説明しています。,AzEditはそれ自身Prologで記述されています。,そしてインタプリタではそれをAZ-Prologコンパイラでコンパイルし、コンパイル組込述語として組み込まれています。,このためAzEditのソースファイルを変更した後にコンパイルをしなおす必要があります。,(コンパイル方法については「7.コンパイラ」を参照してください。),なおここの説明は、Prolog言語に熟知されていることを前提とします。,もちろん標準のAzEditをそのまま使用する場合には、ここの知識は一切必要ありません。,以下の説明は、AzEditのソースファイルを見ながら読むとわかりやすいでしょう。,(1)AzEditのしくみ,上記のようにAzEditはPrologで記述されていますが、実際にはほとんどの基本機能(エディタバッファ操作)は専用の「標準組込述語」で実現されています。,簡単に言えばAzEditのソースではそれらの専用の「標準組込述語」を呼び出しているに過ぎません。(個々のエディタ専用「標準組込述語」の説明はヘルプを参照してください。),AzEditソースを見ると、50行目あたりから「 e_do/1 」の頭部を持つ節がずらっと連なっています。,これらの節の一つ一つがエディタコマンドに対応しています。,AzEditを起動してキー入力されると、すぐにそのキャラクタコードがこの「 e_do/1 」の引数に渡されます。そして、マッチ(ユニファイが成功)した節の本体(コマンドプログラム)を実行します。,また、2ストロークコマンド(^X* と ESC-*)の場合は、「 e_do/1 」の本体にある「d_keyin/1」によってさらにもう1キャラ読み込んで、「 e_do/1 」からそれぞれ「e_dox/1」「e_dom/1」に渡されて、また「 e_do/1 」と同じように分岐しています。,(2)キー定義の変更,この「 e_do/1 」の引数を変更するだけで、キー割り当てが変更できます。,例えば「CTRL-C(バッファ切り替えコマンド)」を「CTRL-T」に変更するには、「CTRL-C」はキャラクタコード「3」ですから「e_do(3,no)」の節を探して、変更します。,e_do(3):-e_edit(O,O),repeat(_),e_edit(X,(X+1)and7),e_edit,e_doch(O),!.,の頭部の「e_do(3)」を「e_do(20)」に変更するだけでOKです。,また、,e_do(11):-e_register(1,11,11),!,e_dok.,e_do(11):-!,e_kill,e_dok.,のように複数個ある場合は、確実にそのすべてを変更する必要があります。,(3)機能の追加,ここでは例として、「バッファ内の任意のキャラクタ位置にジャンプするコマンド」を追加してみましょう。,さいわい標準のAzEditではCTRL-Jにはコマンドが割り当てられていませんので、ここに割り当ててみましょう。,結論を先に書くと・・・,e_do(10):-!,,e_echo,e_echos("EditBufferPosition(char):"),,e_getln(13,[],L),e_cr_buf(L,I),!,e_jump(I).,なる節を追加することになります。,頭部のe_do(10)は「CTRL-J」のキャラクタコードは「10」ですからこうなります。,本体の各ゴールの説明をしておきます。, e_echo/0 ,エコー行を消す、標準組込述語。, e_echos/1 ,エコー行にメッセージを出す、標準組込述語 e_echo/1 を使った定義述語。, e_getln/3 ,キー入力された文字列をキャラクタコードのリストで返すAzEditの定義述語。第一引数は入力を識別するためのキャラクタコードを指定する。, e_cr_buf/2 ,数字文字列のキャラクタコードのリストを数値に変換するAzEditの定義述語。, e_jump/1 ,引数で指定されるバッファ内の文字位置にドットを移動させる。,このようにコマンドの追加は、「 e_do/1 」またはそれ以下に節を追加することにより簡単にできます。,(4)エラーメッセージの変更・追加,まず、ソースリストから「 e_do00/2 」の節を見つけてください。,この述語は第1引数がエラー番号・第2引数がエラーメッセージとなっています。,該当する部分を書き換えてください。,エラーメッセージに限らず、任意の時点で任意のメッセージを出すことができます。,e_echo,e_echos("メッセージ"),,のゴール列を任意の節に書けばよいわけです。,例えば「CTRL-X CTRL-S」コマンドでリコンサルトするときに「Reconsult」と表示させるならば、,e_dox(19):-!,,e_pos(P),e_jump(0),e_markend,e_doxs,e_jump(P),,e_echo,e_echos("Reconsulted").,なる節を、,e_dox(19):-!,,e_echo,e_echos("Reconsult").,e_pos(P),e_jump(0),e_markend,e_doxs,e_jump(P),,e_echo,e_echos("Reconsulted").,とします。"}); htmllist.push({"file":"manuals/manual_azedit.html#azedit_4","title":"9-12-4.制限および注意事項","text":"9-12-4.制限および注意事項,キー割り当てが重複すると正常な動作は保障されませんから、変更は慎重に行う必要があります。"}); htmllist.push({"file":"manuals/manual_function-1.html#other","title":"9-13-1.概要","text":"9-13-1.概要,ここでは、インストールディレクトリの「system/pl」以下に格納されているProlog言語によって記述された述語の説明をおこないます。,標準インタプリタにはコンパイル、リンクされていますが、ユーザプログラムをコンパイルし、これらを利用するときは、このファイルを同時にコンパイルリンクしてください。"}); htmllist.push({"file":"manuals/manual_function-1.html#other_2","title":"9-13-2.詳細","text":"9-13-2.詳細,(1)iso_pred.pl,Prologによって記述された、ISO組込述語です。,個々の述語の詳細は、述語リファレンスに解説されています。,<含まれる述語一覧>, abolish/1 、 once/1 、 atom_concat/3 、 atom_codes/2 、 atom_chars/2 、 number_chars/2 、 char_code/2 、 get_char/1 、 get_char/2 、 open/3 、 current_predicate/1 、 current_prolog_flag/2、set_prolog_flag/2 、 copy_term/2 、 sub_atom/5 、 uppercase_atom/2 、 lowercase_atom/2 、 downcase_atom/2 ,(2)setof.pl,解の集合を求める述語です。, findall/3 ,求めた解の集合を返します。, setof/3 ,求めた解の集合をソートして返します。, bagof/3 ,解が求まった順にかえします。, setof/4 ,第4引数で setof/3 のソート順(昇順、降順)を指定できます。, setof/3 の定義は次となっています。,setof(X,G,L):-setof(X,G,L,asc).,第1引数:(+)var(解の集合を取りたい変数),第2引数:+goal(解を発生するゴール),第3引数:-var(ゴールの全ての解のリスト),第4引数:+atom asc (昇順)またはdec(降順),<例>5クイーンの解を求める述語をqueen(5,X)とすると、その全解を求めて表示させるには以下のようにします。,| ?-queen(5,X),write(X),nl,fail.,[2,4,1,3,5],[3,1,4,2,5],[1,3,5,2,4],[2,5,3,1,4],・,・,・,no,この全解を、1つのリストの中に入れるにはbagof/3を用いて、,| ?-bagof(X,queen(5,X),L).,X = X,,L = [[2,4,1,3,5],[3,1,4,2,5],[1,3,5,2,4]・・・],<例>集合を求めたい解が複数ある場合には、次のようにします。,| ?-setof((X,Y),append(X, Y,[ a,b,c]),L).,L= [([],[a,b,c]),([a],[b,c]),・・・・・・],自由変数(第一引数に指定されていない変数)は自由変数ごとに解の一覧を出力します。,| a(a,1).,| a(a,2).,| a(b,3).,| a(b,4).,| ?-bagof(Y,a(X,Y),L).,Y = Y,,X = a,,L = [1,2];,Y = Y,,X = b,,L = [3,4];,no,自由変数を無視して解をとるには第二引数のゴールに該当変数を "^"で繋げます。,| ?-bagof(Y,X^a(X,Y),L).,Y = Y,,X = X,,L = [1,2,3,4];,no,自由変数が複数あるときは、次のようにしてください。,| ?-bagof(X,(A,B,C)^a(X,A,B,C),L).,<含まれる述語一覧>, findall/3 、 setof/3 、 bagof/3 、 setof/4 ,、s_qsort/3,※ findall/3 、 setof/3 、 bagof/3 はISO述語です,(3)utility.pl,Prologで定義された各種ユーティリティ述語です。, atom_appends/2 ,第一引数のリストの全要素を結合したアトムを返します。,リストの要素は全ての項が可能です。,| ?-atom_appends([a(1),3,sushi,1.2],L).,X      = X,,L      = a(1)3sushi1.20000000000000, local_time/1 ,現在の年、月、曜日、日、時、分、秒、ミリ秒を返します。,| ?-local_time(X).,X = [2007,2,3,21,11,8,19,625], p_puts/2 ,第一引数のストリームに第二引数の文字列をputします。,| ?-p_puts(con,"abc").,abc, get_chars_list/4 ,指定入力ストリームから指定区切り文字までの文字列を返します。,第1引数:+入力ストリーム,第2引数:+区切り文字コード,第3引数:-ファイルが終了した場合は end継続行があるときはcontを返す,第4引数:-指定区切り文字までの文字列リスト,| ?-see('queen.pl',S),repeat,get_chars_list(S,31,X,L).,S = fp_b8e568,,X = cont,,L = [47,42,32,32,32,81,85,69,69,78,46,80,76,32,32,32,42,47];,S = fp_b8e568,,X = cont,,L  = [58,45,32,109,111,100,117,108,47,102,97,115,116,46];,   :,S = fp_b8e568,,X = end,,L = [],yes, write_list/1 ,リストの要素を標準出力します。,| ?-write_list([a,1,b(c),[1,2]]).,a1b(c)[1,2], write_listnl/1 ,上記の最後に改行を出力します。, my_system_name/1 ,起動システム名を返します。C言語のargv[0]に相当,| ?-my_system_name(X).,X = prolog, read_line/4 、 atom_appends/2 、 local_time/1 、 p_puts/2 、 get_chars_list/4 、 write_list/1 、 write_listnl/1 、 my_system_name/1 、 rexpl/3 、 rexpl/4 、 rexpl/5 、 rexpl/6 、 pattern_compile/2 、 rexpl_search/6 ,Prologで書かれた正規表現文字列探索ユーティティ,AZ-Prolog(Version5以降)にはRuby等で定評のある正規表現パッケージ「鬼車」が含まれていますが、こちらはVersion4においてPrologにより実装された正規表現検索です。,前バージョンのプログラムの互換性を保つためと、Prologによる実装ならではの機能があるために付属しておりますが、大容量、多量の文字列検索を高速におこなうには「鬼車」を利用することをお勧めします。, pattern_compile/2 ,第一引数のパターンをコンパイルし第二引数に返します。,パターンを繰り返し利用するときに最初に一回のみ使います。, rexpl_search/6 ,第一引数が検索対象文字列、コンパイルしたパターンが第2引数であるほかはrexpl/6と同じです。, rexpl/3 , rexpl/4 , rexpl/5 , rexpl/6 ,非決定性述語。バックトラックしながら、検索解をかえします。,rexpl/3 は、下記 rexpl/6 の前3引数、 rexpl/4 は前4引数、 rexpl/5 は前5引数のみの述語です。,| ?-rexpl,(String,,Pattern,,Get,,Else,,Before,,Parts,).,検索対象文字列リスト(または、atomic,Float,Term),検索パターン(文字列List,Atom,Atomic-List),検索された文字列リスト,検索残り文字列リスト,検索された文字列リストまでの文字列,部分検索文字列リストのリスト,<例>,| ?-rexpl("test Port 3: 324Kbps,NM 606 next else ",,"Port[ ]*3:[ ]*([0-9]+)Kbps,NM[ ]*([0-9]+)",,A,B,C,[X,Y]).,A = "Port 3: 324Kbps,NM 606",B = " next else ",C = "test ",X = "324",Y = "606",第1引数:対象文字列リスト,文字列リスト,<例> "abcdefg hijke",アトム/数値,<例> 'abceef adsf' 124563 123.2233,評価式, 1)call(X,述語(X))のとき、述語(X)を評価した結果のXを対象文字列とします。,| ?-rexpl(call(Z,atom_append(abc,def,Z)),"b[a-z]{2}",Y).,Y = "bcd", 2)is(X,計算式)のとき、計算式を評価した結果のXを対象文字列とします。,| ?-rexpl(Z is 3*sin(0.5),"¥.[0-9]{5}",Y).,Y = ".43827",その他の項,a(bcd,e) は"a(bcd,e)" と等価(変数が含まれるときは要注意),第2引数:正規表現検索パターン,①,後述のパターン記述子と任意の文字列からなるパターンの文字列リスト、またはアトム。,②,アトムと数値からなるリストでこれらを結合したものがパターンとなる変数は、述語評価時までに値が決定されている必要がある①と区別するために、関数子 pattern/1の引数として与える。,<例>pattern( [ 'Port[ ]*:',3,'[ ]*' ] ),検索正規表現に記述可能なパターン記述子,.,任意の1文字とマッチ,(ダブルバイト文字も1文字。ただし、kanji_mode(_,on)のとき),[],角かっこに囲まれた文字のうちの任意の 1 文字、または、ハイフン (-) で区切られた文字範囲のうちの任意の1文字にマッチ。,たとえば、b[aeiou]d は bad、bed、bid、bod、および bud にマッチ。,また、r[eo]+d は red、rod、reed、および rood にはマッチするが、reod や roed にはマッチしない。x[0-9] は x0、x1、x2 などにマッチ。,角かっこ内にカレット (^) を指定すると意味が反対になる、カレットに続く文字以外のすべての文字にマッチ。,たとえば、x[^0-9] は xa、xb、xc などにはマッチしますが、x0、x1、x2 などにはマッチしません。,^とそれ以外は混在可能。順序は問わない。,<例>[a-z^e-h^40-9],a~z、0~9のうちe~hと4を除いた文字とマッチする。,すなわち、"abcdijklmnopqrstuvwxyz012356789" のどれかとマッチ。,^指定のみで、メンバー指定が含まれないときは、含まれてはいけない文字だけを指定されたとみなす。,(s1|s2|...),文字列 s1 または s2 または ... とマッチします。,文字列には正規表現が使用できます。,(s1),文字列 s1 とマッチします。部分文字列として、順番にリスト化されます,文字列には正規表現が使用できます。,s1のなかにさらに(s0)があるときは結果は入れ子リストとなります。,s1のなかに|があるとORとみなされるので、必要があるときは、エスケープします。(s1¥s2),部分パターンの指定は再帰的です。たとえば、"abc(def(ghiq) (aaa)) "はトップレベルで一要素の部分パターン、部分パターンのなかにさらに2要素の部分パターンを含みます。,^,行の先頭にマッチします。正規表現の最初にあるときのみ有効です。,$,行の末尾にマッチします。正規表現の最後にあるときのみ有効です。,繰り返し,*,直前にある文字または正規表現の0回以上の繰り返しにマッチします。,たとえば、ba*cは bc、bac、baac、baaacなどにマッチします。,+,直前にある文字または正規表現の1回以上の繰り返しにマッチします。,たとえば、ba+c は bac、baac、およびbaaac にはマッチしますが、bc にはマッチしません。,?,直前にある文字または正規表現の0回または1回の繰り返しにマッチ。,たとえば、ba?c は bac、bc にはマッチしますが、baac にはマッチしない。,{数値},直前にある文字または正規表現の数値の回数繰り返しにマッチ。,エスケープ文字 ( ¥ ),¥n,改行コード(Asci 31)とマッチ,¥t,タブ(Asci 9)とマッチ,¥b,バックスペース(Asci 8)とマッチ,¥(7),アスキーコード7とマッチする。,"(7)"とマッチさせたいときは、"¥(¥7¥)",¥N,N:一桁数字 (¥1...¥9) 部分パターンのN番目とマッチします。,¥Any,Any たとえば、¥[ は [ 、 ¥- は -、¥¥ は ¥とマッチする"}); htmllist.push({"file":"manuals/manual_appendix.html#benchmark","title":"10-1.ベンチマークプログラム","text":"10-1.ベンチマークプログラム,プログラムの格納場所,ベンチマーク起動プログラム一式は次の場所に格納されています。,Makefileがありますので、ディレクトリごと作業場所へコピーしてLinuxではコンパイルしてください。(Windows版ではコンパイル済みです。),Windows:,%AZProlog%¥bench,Linux: ,${AZProlog}/share/azprolog/bench,Mac:,${AZProlog}/share/azprolog/bench,コンパイル,ベンチマーク用プログラムはSICStus-Prolog様のサイトにあるものを利用します。,http://sicstus.sics.se/performance.html からダウンロードして解凍し、内容物すべてを「bench/source」下へコピーし「bench」下でmakeします。,( Windowsで再コンパイルするときは、 ~/xxxx/bench> nmake ),起動,ターミナルからbenchmarkを起動すると次のメニューが表示されます。,番号または各メニュー項目の頭文字(r,s,l,t,g,b,e)を投入します。,<例>,>,1) Run All BenchMark Program (if Added,Parameter File Load),2) Save AZ-Prolog-Benchmark-Result to Current Directory,3) Load All Result-File From Current Directory,4) Table-Style Result Display,5) Graph-Style Result Display,6) Break to Interpreter (Type "?-unbreak." To Return Here),7) Exit,Enter No.>r <== "r"の投入でベンチマークが走ります,Module名のプログラムを()内の回数繰り替えした秒数が表示されます。,****** Running Benchmark Programs :: AZ-Prolog.V8 ******,ModuleName Verify Iterate C-Compile Byte-Compile Interpreter [SWI-Prolog],-----------+-CBIO-+-------+----------+-------------+-------------+------------,boyer [Tttt] 100 0.796 (1) 1.892 (2.37) 4.970 (6.24) 2.506 (3.14),browse [Tttt] 100 1.319 (1) 2.360 (1.78) 4.375 (3.31) 2.957 (2.24),「C-Compile」がフルコンパイルコードでの処理時間,「Byte-Compile」がバイトコンパイルコードでの処理時間,「Interpriter」がインタプリタでの処理時間,他社製Prolog処理系との比較,同ディレクトリには他社製Prolog処理系用起動バッチファイル「iso_main_swi.pl」が含まれています。,SWI-Prolog がインストールされているとして、次の手順で結果を“SWI-Prolog.rslt”に出力します。,~/xxxx/bench$ swipl,Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.10.4),Copyright (c) 1990-2011 University of Amsterdam, VU Amsterdam,For help, use ?- help(Topic). or ?- apropos(Word).,?- [iso_main_swi].,結果は、ベンチマークメニューの「l」コマンドで読み込みます。,Enter No.>l [AZ7-B.rslt,AZ7-C.rslt,AZ7-I.rslt,SWI-Prolog.rslt] Loaded,「t」コマンドでテーブルスタイルで結果の表示をします。,Enter No.>t,>,ModuleName Verify Iterate C-Compile Byte-Compile Interpreter [SWI-Prolog],-----------+-CBIO-+-------+----------+-------------+-------------+------------,boyer [Tttt] 100 0.796 (1) 1.892 (2.37) 4.970 (6.24) 2.506 (3.14),browse [Tttt] 100 1.319 (1) 2.360 (1.78) 4.375 (3.31) 2.957 (2.24),chat_parser [Tttt] 100 0.205 (1) 0.691 (3.37) 0.861 (4.20) 0.675 (3.29),crypt [Tttt] 10000 0.428 (1) 1.227 (2.86) 2.295 (5.36) 2.865 (6.69),deriv [Tttt] 100000 0.191 (1) 0.365 (1.91) 0.545 (2.85) 0.495 (2.59),dynamic_uni [Tttt] 10000 0.306 (1) 0.817 (2.66) 1.037 (3.38) 0.827 (2.70),fast_mu [Tttt] 10000 0.132 (1) 0.262 (1.98) 0.609 (4.61) 0.525 (3.97),flatten [Tttt] 100000 0.763 (1) 1.881 (2.46) 4.106 (5.38) 3.083 (4.04),itak [Tttt] 100 0.854 (1) 1.069 (1.25) 1.220 (1.42) 1.523 (1.78),meta_qsort [Tttt] 5000 0.433 (1) 0.988 (2.28) 2.302 (5.31) 1.036 (2.39),mu [Tttt] 10000 0.093 (1) 0.196 (2.10) 0.433 (4.65) 0.376 (4.04),nreverse [Tttt] 100000 0.188 (1) 0.350 (1.86) 3.027 (16.1) 1.792 (9.53),nreverse_bu [Tttt] 100000 0.191 (1) 0.279 (1.46) 0.444 (2.32) 1.821 (9.53),poly [Tttt] 1000 0.679 (1) 1.330 (1.95) 2.389 (3.51) 2.170 (3.19),primes [Tttt] 10000 0.105 (1) 0.306 (2.91) 0.815 (7.76) 0.777 (7.40),prover [Tttt] 10000 0.124 (1) 0.273 (2.20) 0.603 (4.86) 0.379 (3.05),qsort [Tttt] 100000 0.645 (1) 1.644 (2.54) 3.963 (6.14) 3.161 (4.90),queens [Tttt] 10000 0.143 (1) 0.280 (1.95) 0.981 (6.86) 0.988 (6.90),query [Tttt] 100000 0.496 (1) 1.700 (3.42) 2.231 (4.49) 3.374 (6.80),reducer [Tttt] 500 0.258 (1) 0.741 (2.87) 1.135 (4.39) 0.805 (3.12),sendmore [Tttt] 500 0.395 (1) 1.074 (2.71) 2.971 (7.52) 3.441 (8.71),simple_anal [Tttt] 500 0.119 (1) 0.340 (2.85) 0.607 (5.10) 0.438 (3.68),tak [Tttt] 1000 0.955 (1) 2.911 (3.04) 10.33 (10.8) 5.902 (6.18),unify [Tttt] 20000 0.447 (1) 1.470 (3.28) 3.665 (8.19) 2.374 (5.31),zebra [Tttt] 500 0.284 (1) 0.317 (1.11) 0.594 (2.09) 0.717 (2.52),-----------+-CBIO-+-------+----------+-------------+-------------+------------,Total(Average) 10.54 (1) 24.76 (2.37) 56.50 (5.47) 45.00 (4.71),Verify列の[Tttt] は各プログラムの結果がすべて等しいことを示しています。,()内の数字はAZ-Prologのフルコンパイルコードの実行時間を1としたときの倍率です。"}); htmllist.push({"file":"manuals/manual_appendix.html#azlint","title":"10-2.AZLINT","text":"10-2. AZLINT,AZ-PrologコンパイラでPrologソースのリント(プログラム・チェッカー)をおこなうことができます。従来はazlint.exeという独立したスタンドアローンアプリケーションでしたが、Ver7からはコンパイラオプションに「/lint」をつけることで、コンパイルせずに診断のみをおこなうことにしました。,C:¥>azpc -p /lint ファイル名並び {/log} ↓,「/log」を付けると、画面と同時に、azpc.logというファイルに診断内容を出力します。 各ファイル、1モジュール毎に次のような情報を得ることができます。,(1)シンタックスエラーのチェック,(2)決定性にコンパイルされる述語の一覧,(3)非決定性にコンパイルされる述語の一覧,(4)インタプリティブコールとなるゴールの一覧,(5)使用している組込述語の一覧,(6)extern宣言群のうち、使用しているものの一覧,(7)組込述語のオーバーライト定義のワーニング,(8)public宣言をしている述語が1つもないときそのワーニング,(9)無視するpublic宣言、無視するコマンド,(10)publicでない述語でモジュール中でも使われていない述語の一覧,ただし、これらの情報は「コンパイルされた場合にどうなるか」ですので、インタプリタコード上では非決定であってもコンパイル時には決定性述語という場合もあります。(主にモード宣言に関して発生する点です。ただしインタプリタ上でも厳密にモード宣言どうりに使われていれば、効率上はともかく同じ結果にはなります。),各情報について順番に説明しながら、azlintを使ったデバッグについても言及しましょう。,(1)シン夕ックスエラーのチェック,ファイルにシン夕ックスエラーがあると、その節位置番号(つまりファイル中の何番目に書かれている節か、であって述語の何節めかではありません)とエラーとなった周辺の内容を表示して処理を停止します。,シンタックスエラーは、単純な括弧の対応不良、ピリオドの付け忘れといったレベルからオペレータの定義内容に係わる複雑なものまで多岐にわたりますから、エラー箇所の前後を注意して良く見る必要があります。オペレータやオペレータと同じアトムを使っている場合は、まずオペレータ定義の内容を調べて下さい。大抵は括弧を補ったり、正規の表現にすることで何とかなります。,<例>,test(X):-X= = spy → true.,= = , spy, →,がオペレータ定義,↓,test(X):-X = =(spy)→ true.,シンタックスエラーはインタプリタ上で、“echo(_,on).”としてからコンサル卜するか、AzEdit上でコンサル卜することでも判りますが、AZLINTが最も簡便です。,(2)決定性にコンパイルされる述語・非決定性にコンパイルされる述語,決定性に書ける処理(述語)は決定性にすべきです。メモリ効率処理効率が違って来るからです。決定性と判定された述語は、他モジュールで使う(他モジュールでextern宣言する)ときにはその情報を付加しておきましょう。(detプレフィックスを付ける),<例>,: extern det :述語名/アリティ.,決定性にするには、カットオペレータ、モード宣言を積極的に使うことのほかに、externの述語を使うときにその述語が決定性であるかどうかも重要です。,<例>,決定性とならない 決定性となる,append([],L,L). append([],L,L):-!.,append([A|L],B,[A|C]):- append([A|L],B, [A|C]):-,append (L,B, C). append(L,B,C).,または左の定義のままで,:-mode append(+,+,-).を追加する。,決定性になるように記述したつもりでも、非決定性と判定されたときは要注意です。本来のロジック上の誤りである場合以外に、バグが潜んでいる可能性があります。,a),externの述語を使っており、これが決定性なのにdet:宣言がない、またはextern宣言そのものを忘れ、イシタプリティブcall(組込が非決定述語,b),ゴールの一部にスペルミスした述語callがあり、インタプリティブcallとなっている。,c),モード宣言の引数ミス。,d),ピリオドとカンマをまちがえて次の単位節を最終ゴールと見なしている。,(意外に多いミスです。),<例>,a:-b,c,←本来はピリオド。,b.,(3)インタプリティブcallとなる述語,本来、動的に「assert」または「consult」して使われる述語以外のものが表示された場合は,前項の中のa)、b)であることは間違いありません。,(4)使用組込述語の一覧,一部の組込述語(主に画面制御用)を使っているプログラムは、コンパイルオプションとして「/curses」または「/i」が必要です。,使われている組込述語の一覧を見ることでチェックできます。,(5)組込述語のオーバーライト定義のワーニング,インタプリタでは、組込述語と同じファンクタ、アリティを持つ述語のコンサルトはエラーとなりますが、コンパイルすることはできます。,すなわち、低レベルの組込述語を組み上げて上位の組込述語の動作を定義しなおす(putを使ってwriteを最定義、getを使ってreadを最定義する等)ことなどができます。ただし、こうした意図でないのにこのこのワーニングが出たときは、明らかにソースファイル中のミスです。,<例>,a:-b,, , , ,c.,←,ピリオドとカンマの書きまちがい。, , ,write(a)., , , , ,↑, , , , ,write/1の定義になってしまう。,(6)使われていないスタティック述語の一覧,AZ-Prologでは、外部モジュールから呼ぶことの出来る述語は、publicの宣言をするようになっています。,:-public 述語名/アリティ.,:-publicall.(全述語),とすることで、他モジュールから呼ぶこともできますし、インタプリタからも使うことができます。(組込述語として登録される)。,もう1つ書き方があり、,:-public invisible :述語名/アリティ.,とすると、組込述語の登録は行いません。すなわち、他モジュールで使うことはできますが、必ずそのモジュールではextern宣言を入れなければなりません。,publicでない述語は、モジュール内のみにおいて使うことが出来ます。言い換えると、他の述語のサブ述語となります。,こうした述語を「static述語」と呼びます。static述語は他から見えませんので、同じ述語名、アリティのものが他モジュールにあってもリンクエラーを起こすことがありません。,ただし、同一モジュール中でまったく使われていないstatic述語は外からも呼ばれないので、結局はムダとなります。開発中では良く起きることではありますが、完成したアプリケーションをコンパイルするときには、ファイルから削除するかコメントにしておきましょう。,(7)定義述語の一覧,多くの節からなる述語で引数の数のミスをした節が混じっていると、当然のことながら別述語となってしまいます。一覧表を見て同一述語名で引数違いが含まれていれば、意図したものか見なおしましょう。,(8)その他のワーニング,前記の説明で十分でしょう。必要に応じて役立てて下さい。,(9)その他の使い方,AZ-Prologコンパイラでは、モジュール単位にオブジェクトになり、ファイル中には任意にモジュール宣言を入れることになっています。この時、自己モジュールになく、他モジュール中で定義されている述語を使うときは、extern宣言を入れた方が、直接関数呼び出しとなり、高速化されます。,しかし、実際問題として開発中に複数モジュール中の定義を常にチェックしながら宣言を書いていくのも面倒です。,こんな場合には、「azlintでlogをとり、そのログファイルをエディタに読み込んで、“interpritive call”として出力されている述語名一覧を切り出して、extern宣言に一括変換したものを元のファイルに追加すれば簡単に出来ます。,(10)その他,Prologによくあるバグで、「Lint」には反映されないものとして変数名のミススペルがあります。Prologは変数宣言の必要も型指定も不要で、また未束縛変数であっても引数として許されるので、他言語のように、コンパイル時やリントユーティリティではチェックしようがなく、実行時に組込述語でエラーが発生してわかる場合があります。,ANS=3,X is Ans+4,,……,〈実行時エラー〉, , ,〈別変数となるケース〉,次のようなケースではケースをよくながめる以外ないでしょう。,定義,a(l,one), ,実行,?-SP=2,a(Sp,X)., ,a(2,two), , , ,述語情報の中に、頭に数字の付いた定義したおぼえのない述語が含まれていることがありますが、これはLint自身がソースプログラムを読み込む時に、解析しながら、展開/たたみ込みをして生成したものです。,主に節中にOR述語、IFThen、ゴール列を引数とした述語(call、errorsetなど)などの切り出し部分です。,「azlint」は、AZ-Prologコンパイラのソースー次解析部と同一ルーチンを使って記述されています。"}); htmllist.push({"file":"manuals/manual_appendix.html#systemprogram","title":"10-3.システムプログラム","text":"10-3.システムプログラム,パッケージにはAZ-Prologの機能拡張プログラムが付属しています。,カスタマイズインタプリタの生成、スタンドアローンアプリケーション生成など、必要に応じて作業場所へコピーし、コンパイルしてください。,プログラムの格納場所,Windows:,%AZProlog%¥system,Linux: ,${AZProlog}/share/azprolog/system,Mac:,${AZProlog}/share/azprolog/system,各プログラムの概要,system/ext/,拡張ライブラリ(.dll .so .dylib) のソースとMakefileです。,azedit、clp、mecab、oniguruma、redis、websock、socket などのディレクトリごとに分かれています。,system/C/,C言語で記述された拡張用ソースが格納されています。,system/make/,インタプリタの再Make参考Makefile,azpc入力ファイルがあります。,system/pl/,機能拡張、スタンドアローンアプリケーション用のprologソースです。,<システムプログラム>,azserve.pl,OLEオートメーションサーバのトップレベル述語,prologcgi.pl,CGI用インタプリタ"prologcgi"トップレベル述語,mlt_child.pl,並列処理用子プロセストップレベル述語,mlt_parent.pl,並列処理用親プロセス述語,setof.pl,setof,bagof,findall,s_qsort のソース,iso_pred.pl,Prologで記述されたISO 19述語, abolish/1 once/1 atom_concat/3 atom_codes/2 atom_chars/2 number_chars/2 char_code/2, get_char/1 get_char/2 open/3 current_predicate/1 current_prolog_flag/2 set_prolog_flag/2, copy_term/2 sub_atom/5 uppercase_atom/2 lowercase_atom/2 downcase_atom/2 number_codes/2,utility.pl,Prolog定義の正規表現などのユーティリティ,odbc_prolog.pl,ODBCをsql風に利用する上位述語,fs_utility.pl,素性構造メタ述語のソース,macro_consult.pl,マクロ制約記述を展開してコンサルトする述語のソース,<ユーティリティプログラム>,cgi2bytecgi.pl,dump.pl,error.pl,puttxt.pl,count.pl,lil2az.pl ,PrologCGIソースバイトコード変換ツール,バイナリファイルの16進ダンプツール,エラーメッセージ変更用ツール,CGIソースをブラウザに出力するプログラム,Prologプログラムの節行数カウントツール,LilFeSプログラムをAZ-Prolog用にコンバートするユーティリティ,ユーティリティプログラムの使い方の例としてcount.pl を動かしてみましょう。,コンパイル:,> azpc -p /e count /no count.pl ,スタンドアローン実行形式プログラム「 count 」が生成されます。,C:¥>count -p ファイル名並び↓,と入力することにより、各ファイルのライン数・節の数・述語数が表示され、最後に全ファイルのライン・節・述語の合計が表示されます。出力をファイルに落としたければ、リダイレクトを使って次のようにしてください。,C:¥>count -p queen.pl setof.pl>outfile↓,Prologの場合、1行中にゴールを並べて書くことがあり、またコメントや空白行を入れて、見易くすることがありますので、エディタ上のライン数がそのままプログラムの大きさにはなりません。,本ユーティリティでは、プログラムだけを扱いますので、ソースの管理に役立つと思います。尚、ライン数のカウントは、頭部は1ライン、ボディ部の各ゴールも各1ラインとし、ORゴール、callゴールなど、ゴールを引数とするゴールは更にそのゴール数を加えています。,その他の用途として、述語に含まれる節数が、どうであるか、また一節に平均して何ライン含まれるかなどの調査にも応用できます。"}); htmllist.push({"file":"manuals/manual_appendix.html#sample","title":"10-4.サンプルプログラム","text":"10-4.サンプルプログラム,パッケージにはAZ-Prologの各機能ごとのサンプルプログラムが付属しています。,ディレクトリごと作業場所へコピーしてLinuxではコンパイルしてください。,プログラムの格納場所,Windows:,%AZProlog%¥sample,Linux: ,${AZProlog}/share/azprolog/sample,Mac:,${AZProlog}/share/azprolog/sample,各ディレクトリでコンパイルして実行させるものは、ソースファイルとともにコンパイラの使い方の参考になるようにMakefileが含まれています。また、各ソースファイルには使い方などのコメントが書かれていますのでお読みください。,各サンプルプログラムの概要,sample/cgi_demo,CGIのデモが格納されています。,環境設定の詳細は、HowToInstall.txtに書かれています。,sample/C_InterfaceSample,C言語で述語を記述するサンプルソース格納されています。,sample/HDP,分散したPrologプログラムをパイプ連結して結果を求めるサンプルです。,実行バッチ(queentest.bat、queentest.sh)で起動します。,コンパイルMakefileが含まれています。,sample/LargeCapacityMemory,大容量のメモリ空間を使うテストプログラムが格納されています。,sample/ext,動的リンクされるようにコンパイルされた拡張ライブラリを使用するサンプルです。,現在は、mecab、redis、websockの三種類です。,sample/neuralnet,バックプロパゲーションニューラルネット述語を使ったサンプルプログラムです。,ソースファイル(font.pl)をお読みください。,sample/oleauto,Windowsのみの機能です。OLEオートメーション機能のサンプルプログラムです。,readole.txt に詳細が書かれています。,sample/parallel,並列処理のサンプルプログラムが格納されています。,1)AZ-Prologインタプリタに、parallel_test.plをコンサルトし、|?-test. で全実行します。,2)pentomino.exe を起動し、|?-menu. で実行し、複数の方法でペントミノパズルを解きます。,コンパイルバッチ(make_pen.bat)が含まれています。,sample/clp,制約論理のサンプルプログラムです。,起動方法などの詳細はファイルに書かれています。,使用方法は各ソースに書かれています。,magic.pl ,sendmore.pl,sudoku.pl,魔方陣を解くプログラムです。,覆面演算の例題です。,数独を解くプログラムです。,sample/nlu,自然言語処理関係のサンプルプログラムです。,trans.pl,DCG による簡単な日英翻訳プログラム,hpsg.pl,ICOTのCU-Prolog付属サンプルのAZ-Prolog書き換え版,素性構造型を使った単一化文法(HPSG)の簡易版です。,jpsg.pl,ICOTのCU-Prolog付属サンプルのAZ-Prolog書き換え版,素性構造型を使った単一化文法(JPSG)の簡易版です。,tree.pl,hpsg.pl jpsg.pl で使われているCU-Prolog組込述語の翻案プログラムです。,lil_hpsg.pl ,東大辻井研究室でのLilFes課題演習・日本語構文解析プログラムのAZ-Prolog版,sample/other,AZ-Prolog.V1から附属している。アプリ使用方法は各ソースに書かれています。,formula.pl ,del_app.pl,s_utility.pl,queen.pl,azlisp.pl,式の展開プログラム(Written by Kaba),appendを含むリスト処理を差分リストへ変換するプログラム,リスト処理例題,マニュアルで説明しているN-Queenのプログラムです,Prologで書かれたLispインタプリタ,サンプルプログラムの使い方の例としてazlisp.pl を動かしてみましょう。,起動方法,> prolog,?- [-'azlisp.pl'].,?-lisp(con).↓,でRead-Eval-Printループに入ります。,S式評価はlisp_Eval(X,V)で、XにPrologのリスト形式で評価するS式を与えるとVにその評価した値が返されます。,LISP言語仕様,*シンタックス,キャラクタコード:32以下の文字は空白文字として扱われます。,「'(シングルクォート)」と「()」、空白」文字以外の文字はアトムを構成する通常の文字となります。大文字、文字の区別はあります。,数字のみからなるアトムは整数となります。,*特殊型式は以下のものがあります。,(quote x):x自身を返す,(progn forml…formn):form1,‥‥,formnを順に評価、formnを評価した値を返す。,(cond clause1‥‥clausen):clause1,‥‥,clausenの第1要素を順に評価する。,最初に「 nil 」以外のものを返した「 clause 」について、第2要素以外を「prognに与えられたように評価し、その値を返す。但し、clauseでただ1つの要素しかもたないときは、その返した値自体を返す。,それ以降の「 clause 」の第1要素の評価はおこらない。,(de function-name argumet-list・body),function-nameが(lambda argument-list・body)の大域的な名前として登録される。,*特殊型式以外のものは関数呼出しとして扱われる。従って、その引数がまず順に評価され、結果のリストに関数がupplyされます。,組込関数として以下のものがあります。,・基本5関数:car,cdr,cons,eq,atom,・(print x):xを出力する。値はx自体.,・(+xy),(-xy):それぞれx+y,x-yを返す。,・(read):入力したS式を返す。,・(terpri):改行の出力。値はt.,・(help):組込関数,特殊型式名,現在定義されている関数名を出力する。値はt.,・(bye):Read-Eval-Printループを抜ける。,・(gefdef fname):fnameの関数定義をラムダ式の形で返す。,・(load file)(save file):現在の関数定義をファイルにロード/セーブする。,<例>,(de append(x y),(cond((eq x nil) y),(t (cons(car x)(append (cdr x) y))))),→ append,(append '(1 2 3) '(4 5)),→(1 2 3 4 5)"}); htmllist.push({"file":"manuals/manual_appendix.html#implement","title":"10-5.システムインプリメンテーション","text":"10-5.システムインプリメンテーション,(1)スタック,AZ-Prologの実行制御には次のスタックが使われます。,グローバルスタック,グローバル変数、及びReadされた項、ユニブ(=../xfy)等で内部的に作られる構造体が積まれるスタックです。,ローカルスタック,Prolgの実行をコントロールする制御フレーム、及びローカル変数、組込述語の引数バッファに使われるスタックです。,トレイルスタック,ユニファイされた変数の情報を記録し、バックトラック時に元へ戻すために使われるスタックです。,尚、本システムはC言語でインプリメントされており、これ以外にマシンスタック(C言語レベルで使用されるスタック)があります。,グローバルスタック・ローカルスタック、トレイルスタックのサイズは、AZ-Prologコンパイラによって再構成されたインタプリタ、または単独実行モジュールを生成するときに指定するようになっています。,(2)Successful pop と Last call Optimization,AZ-Prologでは、スタックの使用量を減らため「 Successful pop 」と「 Last call Optimization 」を行なっています。,Successful pop,ある述語が決定性の終了をしたとき(この述語の実行に「オルタナティブ(他の可能性)がない」という意味です)この節の実行に使われた制御フレーム、ローカル変数部分をローカルスタックから取り除く事を“successful pop”といいます。,このため、組込述語を含む述語の実行が決定的に終了することによって、このゴールは再充足されなくなります(例えそれ以後にそのゴールに新しい可能性が出来たとしても、その新しい可能性は試されない)ので、次のような注意が必要です。,a(1).,b:-a(X),write(X),assertz(a(2)),fail., ,①, ,②, ,?-b.,1,no,ゴール①の実行は、定義節「 a/1 」が一つしかありませんので決定性の終了をし、このゴールに対応する制御フレームをローカルスタックから取り除きます。,このあとで、ゴール②により、「 a/1 」の代替節を「 assert 」してから、「 fail/0 」によりバックトラックしても、①が再充足されることなく、「 b/0 」の実行が失敗します。,非決定性の組込述語も、決定性終了をした場合は同様です。,a(1).,b:-retract(a(X)),write(X),Y is X+1,assertz(a(Y)),fail.,  ,① , ,②,  ,?-b.,1,no,「 retract/1 」は、引数に指定された削除を試みるべき節がヒープ領域に残っている間は非決定性の終了をし、制御フレームが残っていますが、この場合のように一つだけ定義されている節を削除した後では、決定性の終了になります。,Last call optimization,Prologにおいて、再帰はもっとも基本的なプログラミング技法の一つです。,次の例を見て下さい,write_n(0) :-!.,write_n(X) :-write(X),put(32),Y is X-1,write n(Y)., , ,①      , ,|?-write_n(10).,10 9 8 7 6 5 4 3 2 1,yes,「 write_n/1 」は引数の値を出力し、1つずつ減じながら再帰し、引数の値が0になることによって停止します。,「 write_n/1 」の第2節の最後のゴールを実行するとき、この節自体と、それまでの各ゴールにオルタナティブ(他の可能性)がない状態になっています。すなわち、この最後のゴール①が失敗したとしても、この節には、代替節も、各ゴールの再充足もないわけですから、この節自体に要したフレームを残さなくても良いことになります。,このようなフレームを削除することを“Last call optimization”といいます。,この制御は、特に自分自身に再帰している場合(Tail recursion)ばかりでなくともおこなわれます。,また、カットオペレータが使用されることにより節の代替節、再充足すへきゴールがカットされた場合も同様な最適化を行ないます。,リストの結合を行なうプログラム「 append/3 」において次の3つの書き方が可能ですが、①よりも②、③の方がスタックの消費が少なくて済みます。,①,append([A|B],C,[A|BC]):-append(B,C,BC).,append([],L,L).,②,append([],L,L).,append([A|B],C,[A|BC]):-append(B,C,BC).,③,append([A|B],C,[A|BC]):-!,append(B,C,BC).,append([],L,L).,このようにLast callを効果的に生かすと、スタックの使用を押え、実行も早いプログラムにすることができます。,前掲の「 write_n/1 」はローカルスタックが全く延びずに実行することができます。,(3)ガベージコレクション,AZ-Prologは、ヒープ領域・アトム領域・グローバルスタックのガベジコレクション(ちり集め:GC)がそれぞれの領域が不足した場合に起動されます。,グローバルスタックは、バックトラック時に解放されますが、前掲の「 write_n/1 」のようにバックトラックを起こさずに実行するものに関しては、この節の中に現れたグローバル変数が解放されません。(変数Ⅹがグローバル変数の扱いとなる),その結果、グローバル変数領域が不足した時に、必要な変数セルとそうでない変数セルを区分けし、前者のみを回収する処理(グローバルGC)がおこなわれます。,この機構のために「 write_n/1 」は、引数がいくら大きい数値であっても、スタックオーバーフローを起こさずに動くことができるのです。,尚、プログラム全体の流れの中で、部分的にバックトラックを引き起こすことで、グローバルスタックの解放を計画的に行ない、グローバルGCの発生をおこえることができます。,write_n1(X) :- write_n(X),fail., , ,①, ,write_n1(_).,「 write_n/1 」の中でグローバルスタックを多量に使用した後、「 fail/0 」で解放し、GCが発生する前に解放することができます。(ただし、①の中でGCが発生しないという事を前提とします)"}); htmllist.push({"file":"manuals/manual_appendix.html#errmsg","title":"10-6.エラー・メッセージ一覧","text":"10-6.エラー・メッセージ一覧,1,Syntax error,構文エラー。,2,Can't see the file,指定されたファイルをリードオープンできない。,3,Can't tell the file,指定されたファイルをライトオープンできない。,4,End of file encountered,ファイルエンドを越えてリードしようとした。,5,Illegal file name,ファイル名が正しく指定されていない。,6,Too many variables,節または項中の変数が多すぎる。,7,Too complex term,項が複雑すぎる。,8,builtin or C pred exist,組込述語が既に存在しているのにそれと同じ述語名・アリティを持つユーザ述語あるいはシステム述語を定義しようとした。,9,Illegal argument supplied,組込述語に対して正しくない引き数が与えられた。,10,Illegal Goal,整数あるいは未代入変数をゴールとして実行しようとした。,11,Illegal clause,節として認められない。,12,Illegal define tag,システムエラー。,13,Illegal throw tag,throw述語の引数のタグ指定が不正だった。,14,Illegal catch tag,catch述語の引数のタグ指定が不正だった。,15,unknown predicate call,unknown(_,error)を実行後定義されてないゴールを実行しようとした。,16,Heap area exhausted,ヒープ領域(プログラムを入れておく領域)がオーバーフローした。,17,Trail stack overflow,トレールスタックがオーバーフローした。,18,Global stack overflow,グローバルスタックがオーバーフローした。,19,Local stack overflow,ローカルスタックがオーバーフローした。,20,Malloc failed,メモリアロケーションが出来ない。,21,No more break,ブレークレベルが深くなりすぎてこれ以上ブレーク出来ない。,22,Evaluation error: zero_divisor,0による除算を実行しようとした。,23,Too complex arithmetic,数式が複雑すぎて評価出来ない。,24,Evaluation error: Arithmetic Overflow,フロート演算の結果が大きすぎる。,25,Evaluation error: Arithmetic Underflow,フロート演算の結果が小さすぎる。,26,Illegal Arithmetic,値のセットされていない変数などが入った式を評価しようとした。,27,Illegal character code,漢字コードにないキャラクタコードを指定した。,28,Edit buffer no space,エディタバッファがオーバーフローした。,29,Kill buffer no space,キルバッファがオーバーフローした。,30,out of buffer, e_jump/1 でバッファ内にない位置を指定した。,31,^Gerror,CTRL-G がコンソールから入力された。,32,Search string is too long,検索しようとした文字列が長すぎる。,35,Instantiation error,初期化をせず演算を実行しようとした。,36,Type error: integer expected,変数は整数のみ対応。,37,Type error: float expected,変数は実数のみ対応。,38,Type error: number expected,変数は数値のみ対応。,39,Type error: not evaluable,演算式などが評価できなかった。,40,Evaluation error: float_overflow,実数がオーバーフローした。,41,Evaluation error: int_overflow,整数がオーバーフローした。,42,Evaluation error: undefined,変数値が定義域ではない。,43,Evaluation error underflow,変数値がアンダーフローした。,44,Evaluation error: random seed not initialized,乱数のシードが初期化されていない。,45,Type error: predicate_indicator expected,変数は述語指定子(pred/アリティ)のみ対応。,46,Type error: atom expected,変数は文字列のみ対応。,47,Type error: character expected,変数はアトムのみ対応。,48,Type error: list expected,変数はリストのみ対応。,49,Type error: variable expected,変数は未代入変数のみ対応。,50,Type error: byte code expected,変数はバイトコードのみ対応。,51,Atom area exhausted,アトムの文字列格納領域が不足した。,52,Feature name already exists, 同じ素性が二度以上登場する,53,Feature name has to be an atom, 素性がアトムではない,54,Feature and non-feature mixed, <素性と値の対>と素性以外の項とが混在している,55,Typed FS: Type already exists,型がすでに定義されている,56,Typed FS: Attribute already exists,素性がすでに定義されている,57,Typed FS: Supertype undefined,継承元の型が未定義,58,Typed FS: Same type appears twice in supertypes,継承元に同じ型が二度以上登場する,59,Typed FS: Attribute value has an inconsistent type,素性値の型が不整合,60,Typed FS: Unification result not unique,型を単一化した結果が一意に定まらない,61,Typed FS: Attribute-Type is not defined,素性の型が未定義,62,Typed FS: Type&FStructure is inconsistent,型と素性構造が不整合,200,user errors limit, error/1 でユーザエラーの限界を越えた。,225,abort, abort/0 を実行するとこのエラーが発生した事になり errorset/2 で受け止める事が出来る。"}); htmllist.push({"file":"manuals/manual_appendix.html#azedit","title":"10-7.エデイタ(AzEdit)コマンドー覧","text":"10-7.エデイタ(AzEdit)コマンドー覧,カーソルの移動,CTRL-F,カーソルを一文字前に移動,(Forward character),CTRL-B,カーソルを一文字後ろに移動,(Backward character),CTRL-N,カーソルを一行下に移動,(Next line),CTRL-P,カーソルを一行上に移動,(Previous line),ESC-F,カーソルを現在の単語の次に移動,(Forward word),ESC-B,カーソルを一つ前の単語の先頭に移動,(Backward word),CTRL-A,カーソルを行の先頭に移動, ,CTRL-E,カーソルを行の最後に移動, ,CTRL-V,次の画面を表示, ,CTRL-Z,前の画面を表示,(End of line),ESC-,カーソルをテキストの先頭に移動,(View the next screen),ESC->,カーソルをテキストの最後に移動, ,CTRL-X CTRL -X,カーソルとマークの交換,(Exchange),ESC-Space,カーソルの位置にマークを付ける, ,挿入と削除,Return,NLをカーソルの前に挿入, ,CTRL-O,NLをカーソル位置に挿入,(Open line),Tab,タブをカーソルの前に挿入, ,CTRL-Q,特殊文字の挿入,(Quoted insert),CTRL-D,カーソル位置の文字を削除,(Delete character),BS,CTRL -H,カーソルの前の文字を削除,(Back Space),ESC-D,カーソルのある単語を削除,(Delete word),ESC-BS,カーソルの一つ前の単語を削除, ,CTRL-K,カーソルより右を削除,(Kill line),CTRL-W,カーソルとマークの間を削除,(Kill region),CTRL-Y,ESC-D,CTRL-K,CTRL-Wで削除したテキストをカーソルの前に挿入,(Yank),探索と置換,CTRL-S文字列ESC,前向きの探索,(Search),CTRL-R文字列ESC,後ろ向きの探索,(Reverse search),CTRL-S CTRL-S,同じ文字列の前向き探索, ,CTRL_RCTRL-R,同じ文字列の後ろ向き探索, ,ESC_R 文字列1ESC,文字列2ESC,文字列1を文字列2に置き換える,(Replace),ESC-Q 文字列1ESC,文字列2ESC,文字列1を文字列2にキーボードからの指示に従い置き換える,(Query replace),ファイル操作,CTRL-X CTRL-V ファイル名,ファイルをバッファに読み込む,(Visit file),CTRL-X CTRL-I ファイル名,ファイルをバッファに読み込む,(Insert file),CTRL-X CTRL-W ファイル名,テキストをファイルに書き出す,(Write file),プログラム領域への転送,CTRL-X CTRL-S,テキスト全体のreconsult, ,CTRL-XS,領域のreconsult, ,バッファの領域確保・切替・切り離し,CTRL-C,バッファの切替, ,CTRL-X CTRL-B,バッファの切替, ,CTRL-X CTRL-C,バッファを切り離し(領域開放), ,AzEditの終了,CTRL-X CTRL-Z,PROLOGへ戻る, ,CTRL-XZ,画面の下の部分にスクロール領域を設定してPROLOGへ戻る, ,その他のコマンド,CTRL-L,カーソルを中心に画面を再配置, ,ESC-+,AzEditの使用する行数を一行増やす, ,ESC—,AzEditの使用する行数を一行減らす, ,ESC-W,AzEditの使用する行数を最大にする, ,ESC-U,単語を大文字に変換,(Upper case),ESC-L,単語を小文字に変換,(Lower case),ESC-C,単語を先頭だけ大文字に変換,(Capitalize)"}); htmllist.push({"file":"manuals/manual_appendix.html#console","title":"10-8.コンソールヒストリテンプレートコマンド一覧","text":"10-8.コンソール ヒストリ、テンプレートコマンド一覧,ヒストリー,CTRL-X,ヒストリーの表示,テンプレート,CTRL-F,現在の行にテンプレートから1文字コピーする,CTRL-A,現在の行にテンプレートに残っている全ての文字をコピーする,CTRL-E,テンプレート内の1文字をスキップする,CTRL-W,挿入モードに入る。もう1度押すと挿入モードを解除する,CTRL-T,現在の行の内容をテンプレートにコピーする,CTRL-Q,現在行の先頭まで戻り最初の2文字をスキップする,CTRL-U,現在のテンプレートより一つ古いヒストリーをテンプレートにコピーし同時に現在行の最初からコピーする(CTRL-A),(最初のCTRL-UはCTRL-Aと同じ),CTRL-N,現在のテンプレートより一つ新しいヒストリーをテンプレート,にコピーし同時に現在行の最初からコピーする(CTRL-A)"}); htmllist.push({"file":"manuals/manual_appendix.html#iso","title":"10-9.ISO対応一覧","text":"10-9.ISO対応一覧,No.,ISO述語,AZ-Prolog,対応,1,!/0 ,○*1,2,**/2 ,○,3,*/2 ,○,4,+/2 ,○,5,,/2 , ,6,-/1 ,○,7,-/2 ,○,8,(//)/2 ,○,9,(/¥)/2 ,○,10,;/2 ,○,11,</2 ,○,12,<</2 ,○,13,=/2 ,○,14,=:=/2 ,○,15,=</2 ,○,16,==/2 ,○,17,=¥=/2 ,○,18,>/2 ,○,19,>=/2 ,○,20,>>/2 ,○,21,@</2 ,○,22,@=</2 ,○,23,@>/2 ,○,24,@>=/2 ,○,25,¥+/1 ,○,26,(¥/)/2 ,○,27,¥/1 ,○,28,¥=/2,○,29,¥==/2,○,30,truncate/1,○,31,log/1,○,32,abolish/1,○,33,abs/1,○,34,arg/3,○,35,assert/1,○,36,assert/2,○,37,asserta/1,○,38,assertz/1,○,39,atan/1,○,40,atan2/2 , ,41,at_end_of_stream/0, ,42,at_end_of_stream/1, ,43,atom/1,○,44,atom_chars/2,○,45,atom_codes/2,○,46,atom_concat/3,○,47,atomic/1,○,48,atom_length/2,○,49,bagof/3,○,50,call/1,○,51,catch/3 , ,52,ceiling/1,○,53,char_code/2,○,54,char_conversion/2,○,55,clause/2,○,56,close/1,○,57,close/2, ,58,compound/1,○,59,copy_term/2,○,60,cos/1,○,61,current_char_conversion/2,○,62,current_input/1, ,63,current_op/3,○,64,current_output/1, ,65,current_predicate/1, ,66,current_prolog_flag/2,○,67,discontiguous/1 , ,68,dynamic/1, ,69,ensure_loaded/1,○,70,exp/1,○,71,fail/0,○,72,findall/3,○,73,float/1,○,74,float_fractional_part/1,○,75,float_integer_part/1,○,76,floor/1,○,77,flush_output/0,○,78,flush_output/1, ,79,functor/3,○,80,get_byte/1 , ,81,get_byte/2 , ,82,get_char/1,○,83,get_char/2,○,84,get_code/1,○,85,get_code/2,○,86,halt/0,○,87,halt/1,○,88,include/1 , ,89,initialization/1, ,90,integer/1,○,91,is/2,○,92,mod/2,○,93,multifile/1 , ,94,nl/0,○,95,nl/1,○,96,nonvar/1,○,97,number/1,○,98,number_chars/2,○,99,number_codes/2,○,100,once/1,○,101,op/3,○,102,open/3,○,103,open/4, ,104,peek_byte/1, ,105,peek_byte/2, ,106,peek_char/1, ,107,peek_char/2, ,108,peek_code/1, ,109,peek_code/2, ,110,put_byte/1, ,111,put_byte/2, ,112,put_char/1 ,○,113,put_char/2 ,○,114,put_code/1,○,115,put_code/2,○,116,read/1,○,117,read/2,○,118,read_term/2, ,119,read_term/3, ,120,rem/2,○,121,repeat/0,○,122,retract/1,○,123,round/1,○,124,set_input/1, ,125,setof/3,○,126,set_output/1, ,127,set_prolog_flag/2,○,128,set_stream_position/2, ,129,sign/1,○,130,sin/1,○,131,sqrt/1,○,132,stream_property/2, ,133,sub_atom/5,○,134,throw/1,○,135,true/0,○,136,unify_with_occurs_check/2,○,137,var/1,○,138,write/1,○,139,write/2,○,140,write_canonical/1,○,141,write_canonical/2,○,142,writeq/1,○,143,writeq/2,○,144,write_term/2, ,145,write_term/3, ,   *1 詳細は!/0リファレンス参照"});