あなたのコードは推論できますか?

プログラミングの推論について考えるとき、最初に頭に浮かぶのは、論理プログラミングとルールベースのアプローチ、エキスパートシステム、ビジネスルール管理システム(BRMS)です。







一般的なマルチパラダイム言語には、これらのアプローチ実際には含まれていませんが、ライブラリやインターフェースを介して動作します。 なんで? これらの言語は、ある意味で、その本質と矛盾する形式を自分自身で含めることができないためです。 一般的なプログラミング言語は通常、決定論(予想されるデータ、使用シナリオなど)で動作しますが、推論アプローチは通常、不確実性(予測不可能なデータ、使用シナリオなど)で動作します。 どちらの場合も推論は異なります。 前者ではアーキテクトまたは開発者が、後者では推論/ルールエンジンが推論されると主張します。









この二元論のどちらか一方を好むことはできません。 外の世界は決定論と不確実性に満ちており、それらは同じものと現象で組み合わされています。 たとえば、毎日同じ最短ルートで家に帰ることができます。 過去に検索に時間を費やし、その機能を知っています(そのため、ほとんど「マシン上で」実行できます)。 このルートの使用は非常に効果的ですが、柔軟性がありません。 渋滞などの状況が発生した場合、最短ルートが最長になることがあります。 ナビゲーターを使用できますが、これは完全な保証を与えるものではありません。 私たちが道路にいるときに交通渋滞が発生する可能性があり、別のルートを敷設するためのターンはありません。 30分以内に、ナビゲーターによって提案されたルート上で毎日渋滞が発生することを私たちは知っています。 結論は、一度選択したソリューション(再び時間を無駄にしない)と柔軟な方法(状況が変わった場合)のどちらかを選択する方が良いということです。







これらのアプローチをコードで組み合わせることができますか? 現在最も人気のあるソリューション:プラグイン、カスタマイズ、ドメイン固有言語(DSL)、既に述べたルールなど プラグインは、コードを記述する必要性によって制限され、一定レベルの能力を必要とします。 カスタマイズ、ルール、およびドメイン固有の言語は、学習する必要性とそれらが利用できるアプリケーションの機能によって制限されます。 調査を促進し、アプリケーションの最大限の機能にアクセスできますか? 1つの可能な解決策: マークアップ言語を意味します 。 彼は何ができますか?









例として、惑星体積計算を使用してこれを考慮してください。 オブジェクト指向言語の古典的なソリューションは次のようになります。







class Ball { int radius; double getVolume() { ... } } class Planet extends Ball { ... } Planet jupiter = new Planet("Jupiter"); double vol = jupiter.getVolume();
      
      





このコードには、定義、フィールド、メソッド、クラス階層などに十分な理由があります。 たとえば、惑星がボールであり、木星が惑星であるという事実。 ただし、この推論は暗黙的であり、再利用できず、コードと密接に結びついています。 同様のJavaScriptコードでは、規則は推論が隠されています。







 function getBallVolume() { ... } var jupiter = planet.getPlanet('Jupiter'); var volume = getBallVolume(jupiter.diameter);
      
      





意味マークアップを使用する場合:







 meaningful.register({ func: planet.getPlanet, question: ' {_} {}  {} ', input: [{ name: '', func: function(planetName) { return planetName ? planetName.toLowerCase() : undefined; } }], output: function(result) { return result.diameter; } }); meaningful.register({ func: getBallVolume, question: ' {_} {}  {} ', input: [{ name: '' }] }); meaningful.build([ ' { } ', ' {} ' ]); expect(meaningful.query(' {_} {}  {} ')).toEqual([ 1530597322872155.8 ]);
      
      





ただし、状況は異なります。









それだけですか? そうでもない。 これで、主要なプログラミング言語ではない分野、例えば因果関係に入ることができます。 OS_like_OSオペレーティングシステムのインストール方法に関する指示を扱っていると想像してください。 最新のソフトウェアは、そのような指示をテキスト文書として考慮します。 しかし、これはOSのインストールの原因と結果のセットであると想定できます。 この場合、「OS_like_OSのインストール方法」という質問に対する答えを得ることができます。 直接:







 var text = [ '    ', '    USB   ', '   ', '   ' ]; _.each(text, function(t) { meaningful.build(' { } OS_like_OS { } ' + t); }); var result = meaningful.query('{_ @} { } OS_like_OS'); expect(result).toEqual(text);
      
      





推論のために非常に簡単ですか? しかし、これはほんの始まりに過ぎません。 確かに、そのような質問に答えるとき、私たちは原因と結果だけでなく、条件や他の関係でも動作できます。 代替手段や条件を備えた機能へのパスを要求するテストの例を見ることができます。 これはドキュメント以上のものです。 これらは、再利用可能なアプリケーションコンポーネント間の説明と依存関係マップであり、「どのように?」 そしてなぜ?







同様の状況はエラー処理です。 今日のエラーは、せいぜい、何が起こったのかを知ることができる呼び出しスタックを備えた読み取り可能なメッセージです。 最悪の場合、プロンプトのないランタイムエラーメッセージである可能性があります。 意味のマークアップとコードとの統合が改善できるのは、実際に何が起こったのかをより明確にし、おそらく状況を修正するためです。 リストにアイテムを追加する関数の例を見てみましょう。







 // ,  /   . var addEnabled = true; var planets = []; meaningful.register({ func: function(list, element) { if (addEnabled) eval(list + '.push(\'' + element + '\')'); else //    false,    throw " "; }, question: ' {}  {}  {} ', input: [ { name: 'list' }, { name: '' } ], error: function(err) { if (err === ' ') //          return ' {} '; } }); //   ,    meaningful.register({ func: function(list, element) { addEnabled = true; }, question: ' {} ' }); meaningful.build([ 'planets { } ' ]); meaningful.build([ ' { } ' ]); meaningful.build([ ' { } ' ]); meaningful.query(' {}  {}  {} planets', { execute: true }); //     , ..   true expect(planets).toEqual([ '' ]); //    . addEnabled = false; //      meaningful.query(' {}  {}  {} planets', { execute: true, error: function(err) { //      "" ,     meaningful.query(err, { execute: true }); }}); expect(planets).toEqual([ '' ]); meaningful.query(' {}  {}  {} planets', { execute: true }); //      expect(planets).toEqual([ '', '' ]);
      
      





ご覧のとおり、エラー処理の結果はメッセージとコールスタックだけでなく、原因と変数、変数の状態などの複雑なものになる可能性があり、これらはすべて「なぜこのエラーが発生したのか」という質問に答えるのに役立ちます。 これを可能にするには、問題のテキスト記述に基づいてファクトモデルを設計できるときに、要件を策定する段階で準備を開始する必要があります。 たとえば、次のマークアップ:







  {}  { } 142984 4.1887902047864 { }  {}  {}  { } 2 1530597322872155.8 { }  {}  {}  { } 142984
      
      





これは、getPlanetDiameter()およびgetBallVolume()関数のレイアウトおよび期待と見なすことができます。 これに基づいて、実際のモック関数を生成できます。







 function getDiameterOfPlanet(planet) { if (planet === '') return 142984; } function getVolumeOfBall(diameter) { if (diameter === 2) return 4.1887902047864; if (diameter === 142984) return 1530597322872155.8; }
      
      





このようなモック関数を使用すると、すでに推論が可能になり(たとえば、Jupiterのボリュームの計算に役立ちます)、将来のアプリケーションが既存のデータとコードのエコシステムにどのように「適合する」かを評価できます。 さらに、開発者は既にモック関数を実際のコードに置き換えることができます。 つまり、要件、コード、テスト、ユーザーインターフェイス、ドキュメント(構成可能な自然言語構成要素によってサポートされます)の間の対応により、制限されたレイアウト機能、実際の機能、ユーザーインターフェイスの対応する部分、およびドキュメントを同様の方法で操作できます。 これにより、さまざまなタイプのエンジニアリングアクティビティ間の待機サイクルと推論をさらに削減できます。それらを操作するために、完全な実装を待つ必要はありません。







当然、パフォーマンスの問題は実行フェーズにとって重要ですが、 Giant Global Data Graphを構築しようとするセマンティックWebとは異なり、アプリケーションは独自のデータによってのみ制限できます。 より柔軟でグローバルな結論につながることはありませんが(アプリケーションによってのみ制限されるため)、より具体的かつ検証可能です(アプリケーションによってのみ制限されるため)。







だから、あなたのコードは推論できますか? より正確には、これを行うのはコード自体ではなく、コードに基づいた出力マシンですが、これは可能です。 アプリケーションの開発を改善することによって動機付けられるという理由だけで、コードの要件への準拠をよりよく確認できるという事実のため、このアプリケーションまたはライブラリが提供するものを見つけることが容易になるという事実のために機能は、意味のマークアップの形式で利用可能になります)、原因ロジックをアプリケーションロジックとエラーの原因となったロジックに対してより明示的にすることができるという事実のため。







不確実性と決定論の二元性に関しては、おそらく、互換性のないものを結合しようとするのをやめる必要があります。 すべてのアプリケーションの作業は、(a)密結合の静的型付けコード(信頼性、セキュリティ、特定のシナリオの効率に対する要件が増加)および(b)疎結合、動的型付けおよび自然言語のコンポーネント構成(要件なし)として表すことができます信頼性、セキュリティ、アプリケーションのレベルによって規制する必要があり、幅広いシナリオに柔軟に適用できます)。 決定論に最適化された、より柔軟な構造を作成する必要がありますか? 不確実性にもっと焦点を合わせた、より生産的な設計をすることを試みる価値はありますか? ほとんどの場合、ノーとノー。 アプリケーションは高度に専門化されたものであり、自然言語はどのような条件にも、それぞれ独自のものに適応する必要があります。








All Articles