C〓〓〓の論理式のプログラミング言語はきわめて簡単に実現します:運行の原理


カタログ図書館を転載します. http://www.pinlue.com/article/2020/07/1115/5911013668815.html
 
論理式プログラミング言語はきわめて簡単に実現されます.
 
NMini Kanrenの運行原理を説明します.明さんはホワイトボードを叩いてコードを塗り始めました.私たちはいい例から始めました.
KRunner.PrintResult(KRunner.Run(null, (k, q) =>{    var x = k.Fresh();    var y = k.Fresh();    return k.All(        k.Any(k.Eq(x, 1), k.Eq(x, 2)),        k.Any(k.Eq(y, x), k.Eq(y, "b")),        k.Eq(q, k.List(x, y)));}));
 
この問題はもうできました皮さんは例の下に答えを書きます.
[(1 1), (1 b), (2 2), (2 b)]
 
ビビさんが昨日の知識を忘れていないのを見て、明さんは少し喜びました.この答えはどうやって計算しますか?
えっと、それです.皮が急に抜けました.このような問題は幾何学的証明問題のようです.一目で分かる二つの垂直線なのに、本当に手を下して証明するのはなかなか難しいです.皮さんは髪の毛を何本かつかんで、やっと気持ちを整理しました.たぶんすべての条件が可能な組み合わせを見つけることです.そして、計算して解けばいいです.皮さんは言いながら、ホワイトボードに書いています.
うん、実は答えはどうやって出すか分かりました.その中の細部についてはまだよく分かりません.私たちがこれからやるべきことはこの計算過程を明確にして、各ステップがコンピュータで明確に実行できるアルゴリズムを得ることです.
このアルゴリズムは実はあなたが言ったように、すべての可能な条件の組み合わせを探します.各グループの条件の組み合わせは一つの解を求めることができます.また、自己矛盾しています.NMini Kanrenにおける条件はすべて等しい条件であるので、条件セットは置換と見なされ得る.一つの交替は一つの解を生み出すことができます.あるいは無解です.
したがって、次の二つの問題を解決するだけでいいです.
  • は、どのようなデータ構造において、どの順序で巡回置換されますか?
  • は、置換からどのようにして解を算出するか、あるいは無解を判断するか.
  • 分岐を巡回
     
    まず、コードからデータ構造を作ります.このデータ構造は、一定の順序で巡回し、順次置換を生成することができる.
    例のコードは、Eq、Any、Allの3つのターゲットを構成する方法を使用している.この3つの方法から必要なデータ構造をそれぞれ検討します.
    Eq
     
    k.Eq(a,b)構造の目標は何ですか?明さんは平凡そうな問題で始まりました.
    aはbに等しいという意味です.
    孤立して見ると、そうです.しかし、文脈を考慮して、より正確には、文脈においてa=bという条件を追加するべきである.
    ビビさんはちょっと分かりません.emm…多くなりましたが、追加は何が違いますか?
    文字の上から見て、「追加」が多くなったら、目標の解釈は一種の名詞(一組の条件)から動詞(追加条件)になります.このように、目標は一つの条件を表すだけでなく、これらの条件が文脈とどのように結びつくかを表しています.Eqの場合、この結合方式は「追加」です.AnyとAllは他の結合方式があります.
    まだよく分かりませんが、これはAnyとAllの状況を待ってこそ明らかになると思います.もう一つの問題がありますが、文脈は何を指していますか?
    狭義には、コンテキストは、このコードがインタプリタによって実行されたときに、実行されたコードの生成に置き換えられます.
                   
     
    広義では、文脈にはトレース分岐などの制御情報が含まれているはずですが、今はそれを無視します.
    総合的に、Eqの目標について説明すると、この目標を下図で表します.
     
    Any(または)
     
    続いてAnyを見ます.上記の議論に従って、私達はAny目標をどう説明しますか?明さんは引き続き質問します.
    目的を説明するには、二つの面を明確にする必要があります.名詞(条件)と動詞(コンテキストとの結合).最初の例では、k.Any(k.Eq(x,1)、k.Eq(x,2)を例にとる.名詞の面では当然xは1とxは2つの条件ですが、この2つの条件は‘或’の関係です.動詞については、文脈から分岐して二つの分岐があるべきで、一つの分岐にxを追加することは1の条件に等しく、もう一つの分岐にxを追加することは2の条件に等しい.
    いいです.つまり、Eqとは違って、Any操作とコンテキストが結合すると、複数の置換が生成されます.老明は賛辞してうなずいた.パラメータの分枝を一緒に置いて、足し算のようにした.図で示すと、次のようになります.
     
    All(と)
     
    最後はAll…
    これもできます.皮さんは老明を中断しました.K.All(a,b)名詞に条件aと条件bを表します.動詞には文脈を表します.aを先に追加して、bを追加します.
    あなたの話は漠然としすぎます.aとbは複数の分岐があるかもしれませんが、この場合はどうすればいいですか?明さんは続けて聞きました.
    皮さんは最初に作った例を考えて、答えました.この場合はすべての組み合わせ、つまりaの分岐とbの分岐の二つの組み合わせを取ります.最後の分岐数は、a分岐数にb分岐数を乗じたものとする.
    いいです.Any類比を足し算すると、All類比は掛け算です.この図は、冒頭の例におけるAll方法の結合過程を説明する.
     
    これは方向図があり、各辺に条件を追加する過程を示しています.各起点ノード(コンテキスト)から終点までの経路は、上のノードが組み合わせて一つの代替となる.すべてのパスを遍歴して、私たちはすべての代替を遍歴しました.巡回の順序は、解釈器が結果を出力する順序である.
     
     
    アンイ
     
    次はアンイも見に来ます.
    一般的なAnyで使用される一般的なツリー構造は、巡回順である:
     
    Anyiは、分岐を交互に巡回します.
     
    Alliは交替の順序を採用して遍歴します.ここではもう描きません.
    目標(Goal)を再確認する
     
    前の記事では主に構造目標の観点から、異なった方式で構成された目標を紹介しています.
    NMiniKanrenのインタプリタを実現するためには、どのようなタイプのGoalがインタプリタの実装において、より深く理解する必要がある.
    前の議論では、ターゲットの意味はコンテキスト/置換にいくつかの条件を追加し、ゼロ、1つまたは複数の代替を返します.AnyとAllは複数を返すことができます.また、前に議論されていないFailはゼロに戻ります.
    この説明からもわかるように、最も目的のタイプを表すのに便利なのは単一パラメータ関数であり、そのパラメータは置換され、戻り値は置換されたエニュメレージであり、C((zhi)のEnumerableに相当する.
    Goal: (  ) -> Stream
     
    Goal(置換)という関数の呼び出しは、Goalを含む条件を置換に追加し、一連の置換を返します.
    なぜ直接Listを使わないですか?ビビさんはまた質問しました.
    多くの場合、枝の数が多く、さらに無限に多いからです.私たちは一つずつ前の結果を取ればいいです.この場合、Listを使うと、解釈器の効率が大幅に低下し、デッドサイクルにもなります.
    再帰的状況
     
    省略する
    なんですか?ビビが目を丸くした.
    絵を描くのがおっくうです.残して考えてください.
    ソルバーを置換
     
    代替を生成したら、残りは解決です.
    代わりに解く方法は簡単です.小学校の時に習った代入消元法を適用してください.ちょっと見てください.これはどうやって解けばいいですか?説明しながら例を書きます.
    (1) y == x(2) q == (x y)(3) x == 1
     
    結局小学校の難度の問題で、皮さんは一目見て、すぐに理解法があります.x=1は確定しました.(3)を(1)に代入した後、yも1になります.(1)と(3)を(2)に代入し、qを(1)に等しくする.
    解は求められましたが、この手順は通用性があると思いますか?老明虚は目をつけて言って、コンピュータは意識的にあなたのこの蛇の皮の順番を使うことができますか?
    えっと、皮さんは考え込んでいます.代入順のルールを判断するのは面倒くさいようです.あるいは簡単で乱暴なので、すべての順番で代入しますか?
    思ったより複雑ではなく、順番に代入して、逆に代入すればいいです.
    順番に代入する
     
    (1)を(2)(3):
    (1) y == x(2) q == (x x)(3) x == 1
     
    (2)を(3)に代入する:
    (1) y == x(2) q == (x x)(3) x == 1
     
    インタプリタの実装では、条件は一つずつ追加されます.条件を追加するたびに、既存の条件を新しい条件に代入することができます.このステップを代替生成過程に解消します.
    加入条件(1)y==x:
    (1) y == x
     
    加入条件(2)q=(x y):
    (1) y == x(2) q == (x x)
     
    加入条件(3)x==1:
    (1) y == x(2) q == (x x)(3) x == 1
     
    逆の順序で代入する
    (3)を(2)(1):
    (1) y == 1(2) q == (1 1)(3) x == 1
     
    (2)を(1):
    (1) y == 1(2) q == (1 1)(3) x == 1
     
    できます
    これは単なる例にすぎない.実際には無解、自由変数、死のサイクルなどもあります.ここではこれ以上くどくど述べる必要はない.
    再議非演算
     
    NMiniKanrenはなぜ「非」演算を支持しないのかが分かります.
    ビビさんはよく考えてみました.「非」を支持しないどころか、「大」と「小」もだめでしょう.代入消元法によると、NMiniKanrenは同じ条件しかサポートしていません.
    これらの演算をサポートするにはどうすればいいですか?
    条件を拡張するタイプ.等しい条件を除いて,まだ同等でない条件などがある.応答のソルバーアルゴリズムも変化します.
    そうです.変更は大きくないですが、コードが混乱しているように見えます.だから、授業を目的としたら、これを支持しないです.
    結び目
     
    いつの间にか时间はすでに楽しいランチの时间になりました.すると、老明は総括しました.ポイントは二つです
  • は、どのようなデータ構造において、どの順序で巡回置換されますか?
  • は、置換からどのようにして解を算出するか、あるいは無解を判断するか.
  • 第一に、コードから図を作りました.図の各パスは代替に対応しており、経路を巡回する順序は代替の順序である.目標Goalのタイプも明確にしました.
    第二に、私たちは代入消元法を使って、二回にわたって代入してすべての未知の量を解いた.
    次にコードを書いてNMiniKanren解释器を実現しましょう.