プロローグで再確認します。 セブンラインマジック

認識マシンが象の写真に「ムラ」信号で応答する場合、ラクダの画像も「ムラ」であり、著名な科学者の肖像画は再び「ムラ」です。これは必ずしも欠陥があることを意味しません。 彼女はただ哲学的でありえます。

ウラジミール・サフチェンコ、「自分を開く」




1.リファールが大好き。 すぐに!





そのようなプログラミング言語があることを誰もが知っています-リファール。 Refalは1966年に同胞のValentin Turchinによって開発されました。 リファールの運命は複雑ですが、彼の言語はまだ生きていて発展しています。 興味がある人のために、ここにいくつかのリンクがあります:





非常に誇張して、RefalはLispとPrologの混合物であると言えます。 言語構文には、いわゆるパターンとの比較という興味深い機能が1つあります。 「直接結論。」



つまり、たとえば、Refalでパリンドロームを決定するための述語は、次のように記述できます。



Palindrom { = True; s.1 = True ; s.1 e.2 s.1 = <Palindrom e.2> ; e.1 = False ; }
      
      







中括弧内の各行は、パターンマッチングルールです。 各ルールの本文は、記号「=」で区切られています。 サンプル要素はスペースで区切られます。 関数呼び出しは山括弧で書かれています。 「s」と「e」で始まる文字は、特定の種類の変数です。 変数の名前は、ピリオドの後に書き込まれます。





T.O. 回文のこの定義は、次のように読むことができます。





Refalの最新の実装では、モデルとの比較が非常に効率的に実装されていることをキャンセルする必要があります。



2.プロローグ。 魔法が始まります!





RefalにはPrologからたくさんのことがあります。 Prologのサンプルとのrefalovskoe比較のメカニズムの実装を試みます。



始める前に、ヘルパー述語「prefix」を定義します。 述部は、最初の引数が2番目の引数の始まりであるかどうかを確認する必要があります。 2番目の引数の残りは、3番目の引数に示されます。



 prefix([], [X|Xs], [X|Xs]). prefix([X|Prefix], [X|List], Rest) :- prefix(Prefix, List, Rest).
      
      







呼び出し例:



 ?- prefix([1,2], [1,2,3,4], [3,4]). true. ?- prefix([], [1,2,3,4], X). X = [1, 2, 3, 4].
      
      







これで、サンプルと一致するrefalovoeの述語を決定する準備がすべて整いました(述語「rf」と呼びましょう)。 例と同じパリンドロームを使用した「rf」の使用例は次のとおりです(実装自体は少し後です)。



 palindrom([]). palindrom([_]). palindrom(List) :- rf([s(X1), e(Y), s(X1)], List), palindrom(Y).
      
      







ご覧のとおり、この定義は以前にRefalで書いたものと似ています。 refalovの例の4番目のルールは必要ありませんでした。 プロローグ自体は、マッピングの誤った分岐を遮断します。 例の「s」と「e」は通常のProlog用語であることに注意してください。



回文を呼び出す例:



 ?- palindrom("abc"). false. ?- palindrom("abcba"). true . ?- palindrom("aa"). true .
      
      







次に、rf述語の定義に移りましょう。



 rf([X | Pattern], [X|Xs]) :- rf(Pattern, Xs). rf([s(X) | Pattern], [X|Xs]) :- rf(Pattern, Xs). rf([e(X) | Pattern], Xs) :- prefix(X, Xs, Rest), rf(Pattern, Rest). rf([e(X)], X). rf([], []).
      
      







定義について1行ずつコメントします。





3.例





3.1。 最初の例





素晴らしい記事「Prolog、Introduction」は、 PrologRefalコミュニティで提案された問題の解決策を提供します。 問題文:



入力ファイルには2つのASCII行があり、1つは大きなラテン文字のみで構成され、もう1つは大きなラテン文字と2つの特殊文字-*(アスタリスク)および? (疑問符)。 文字列の長さは1〜255文字で、ランダムな順序でファイルに格納できます(ただし、入力データ形式は正しいので、2つしかありません)。 文字のみの行は単語と呼ばれます。 特殊文字を含む行-「?」が含まれるパターン および「*」は、DOSまたはUnixシェルのファイル名のワイルドカードと同じ規則に従って、ワイルドカード文字の役割を果たします。 「?」 任意の1文字を正確に置き換え、「*」は任意の数の任意の文字を置き換えます-0以上(つまり、空の文字列を置き換えることができます)。 単語がパターンに一致する(一致する)場合、プログラムはYESと答え、そうでない場合はNOと答えます。





リファールの解決策:



 Match { s.1 e.2 (s.1 e.3) = <Match e.2 (e.3)>; s.1 e.2 ('?' e.3) = <Match e.2 (e.3)>; e.1 ('*' e.3) = { e.1 : e.11 e.12, <Match e.12 (e.3)>; }; /*empty*/ () = /*yes*/; };
      
      







上記のアプローチを使用して、PrologのRefal述語を書き換えます。



 ischar(H, [H]). match([],[]) :- !. match("*",_) :- !. match(Pattern, Word) :- rf([s(T1), e(E1)], Pattern), rf([s(T1), e(E2)],Word), match(E1, E2),!. match(Pattern, Word) :- rf([s(T1), e(E1)], Pattern), ischar(T1, "?"), rf([s(_T2), e(E2)], Word), match(E1,E2),!. match(Pattern, Word) :- rf([s(T1), e(E1)], Pattern), ischar(T1, "*"), rf([e(_E21), e(E22)], Word), match(E1,E22),!. check:- match("ASDFAASDASDAAASDASDASD", "ASDFAASDASDAAASDASDASD"), match("*", "ASDFAASDASDAAASDASDASD"), match("A?DF?A*ASD*ASDA?DASD", "ASDFAASDASDAAASDASDASD"), \+ match("ASDFAASDADAAASDASDASD", "ASDFAASASDAAASDASDASD").
      
      







もちろん、私たちの定義は、記事「Prolog、Introduction」のソリューションよりもはるかに効果が低いことに注意してください。



3.2。 2番目の例





述語を使用する別の例を次に示します。 文字列の算術式を計算する簡単な述語を定義します。



使用例:



 ?- infix("2+2*2", R). R = 6. ?- infix("1+1+1+1", R). R = 4.
      
      







中置述語に加算と乗算の演算のみを「理解」させます。 次に、ソリューションは次のようになります。



 ischar(H, [H]). infix(A,R) :- rf([e(X), OpPlus, e(Y)], A), ischar(OpPlus, "+"), infix(X,R1), infix(Y,R2), R is R1 + R2,!. infix(A,R) :- rf([e(X), OpMul, e(Y)], A), ischar(OpMul, "*"), infix(X,R1), infix(Y,R2), R is R1 * R2, !. infix(A,R) :- rf([e(X)], A), number_codes(R, X),!.
      
      







他の演算子の実装は独立した研究に任せます。



結論の代わりに





上記のコードは、一意または実用的であると主張していません。 しかし、読者がPrologやRefalのような素晴らしい言語に精通するようになることを願っています。



All Articles