1Cの関数型プログラミング:Enterprise 8環境

最近、関数型プログラミングのアイデアが大衆に浸透する傾向があります。 私にとって、1Cプログラマーとして最も興味深いのは、表形式のデータを扱うときの抽象化のレベルを上げることです。 反復ごとに値を変更する多くの変数でループをコーディングするのは1つのことです。1か月後に「アイデバッグ」(または実際にデバッガーを実行)を実行して、これらのループの仕組みを理解する必要があります。 テーブル全体に適用できる既製のデバッグアルゴリズムを使用すると、期待どおりの結果が得られます。



年々、似たようなサイクルをコーディングしていましたが、この退屈なプロセスで何かをより良くしたいという欲求に染みついていました。 最初は、一般的なSTL C ++アルゴリズムに触発されました。 それから、一般的な開発のために、私はHaskellを研究しました-この言語は本当に認識を変えます。



約2年前、私は日常業務で使用するユニバーサル関数のライブラリを書き始めました。 実践は、このアプローチが機能し、具体的なメリットをもたらすと確信しました。 そしてつい最近、LINQを発見しました。これは.NETプラットフォームでコレクションとの統合作業に使用され、SQLクエリなどの有用なものを生成します。 このような素晴らしいツールを持っているシャープの白いof望がうらやましい!



LINQコアを構成する標準クエリ演算子のライブラリを検討した後、1C Enterprise 8用の同様のライブラリを作成することにしました。



私がこれまでに行ってきた開発-私はゴミを投げます、なぜなら それらは全身的で普遍的ではありません。



関数指向ライブラリを作成する際の主な障害は、組み込み言語のパラメーターとして関数を渡すためのサポートの欠如です。



コレクションを操作するための一般的なアルゴリズムでは、引数として関数が必要です。 たとえば、フィルタリングアルゴリズムは、コレクションアイテムを取得してブール値を返す条件関数を使用します。 テーブルフィールドの変換には、さらに複雑な機能が必要です。 パラメーターとして別の関数に渡される関数は、関数型プログラミングではクロージャーと呼ばれます。



本格的なクロージャーを代替物に置き換えるためのさまざまなオプションを検討しました。バイトコードを解釈する組み込み言語で仮想マシンを作成することもできました。 その結果、文字列としてライブラリに転送された埋め込み言語の式を計算する言語の能力を活用することが最も望ましいという結論に達しました(ソリューションの根拠はプロジェクトのドキュメントにあります)。 次のようになります。

= .("_. > 0",, );







アンダースコアは、関数パラメーター、この場合はソーステーブルの行を示します。 関数がいくつかのパラメーターをとる場合、それらは「_0」、「_ 1」などで示されます。 アルゴリズムに渡される関数は、呼び出し側で既知のデータ(コンテキスト)を使用する場合があります。 例:

= 100;

= .("_. > _.", ("", ), );







変数 "_k"は、If関数の2番目のパラメーターによって渡されるコンテキスト(通常は構造体)の値を取得します。 より複雑な設計を実証するために、やや不自然な例を挙げます。

顧客注文額=テーブル。接続(
     「顧客= _。リンク」、
     「顧客= _0。リンク
     | INN = _0.INN
     | Ordered = _1.Amount ",,
    顧客、注文
 );


最初のパラメーターは、接続のキーフィールドを設定し、最初のテーブル(「リンク」)のフィールド名を2番目のテーブル(「クライアント」)のフィールド名に変換します。 2番目のパラメーターは、結果フィールド(Client、TIN、Ordered)の式を設定します。 「顧客」と「注文」はソース値テーブルです。



組み込み言語を使用して値テーブルのデータを処理することは、この問題に対する最善の解決策ではありません。 埋め込み言語は、SQLクエリよりもはるかに遅く実行されます。 データがデータベースから受信されない場合、またはそのボリュームが小さい場合、および非自明な操作(すべてがクエリで実行できるわけではありません)の場合にのみ、組み込み言語に頼ります。



私は、普遍的なアルゴリズムのように見えるが、実際にはリクエストを形成する関数をライブラリに含めました。

リクエスト= Requests.Select(
     「仕様。命名ASマテリアル、 
     |(Orders.Quantity * Specifications .Quantity)AS Quantity "、
    リクエスト:接続(
        注文、仕様、
         「注文。仕様=仕様。リンク」、
        リクエスト:から(「ドキュメント。生産の注文。生産」)、
        リクエスト。(「参照。仕様。元のコンポーネント」)
     )
 )
結果=リクエスト。実行(,,リクエスト);


なぜこれをしたのですか? 与えられた例は、クエリコンストラクターを作成するためにより速く、より信頼できます。 とにかく通常のクエリ言語よりも読みにくい。 それは本当に芸術への愛からだけですか? それだけではありません。 ライブラリのこの部分は、重複する要素、または可変数のフィールド、サブクエリを含む複雑なクエリを対象としています。 このようなクエリは通常、文字列に接触することで形成されます。これにより、構文、特にコンマとブラケットの配置を監視する必要が生じます。 実際にはこのアプローチをテストしていませんが、これらの場合のライブラリが害よりも良いことを願っています。



現時点では、プロジェクトのドキュメントと関数ヘッダーは完全に準備されています。 私はまだ関数の実装に着手していませんが、非常に正確にそれを想像しています-プロジェクトは非常に詳細に解決されました。 関数の配列全体をテストすることはさらに困難です。 同僚からフィードバックをもらいたいです。 妥当なコメント/提案があれば、実装を開始する前にライブラリインターフェースを開く準備ができています。 既製のモジュールも公開されます。 また、特定のアカウンティングアルゴリズムを追加してライブラリを拡張する予定です。ベースによる配布、Fifoによる配布などです。



参照:

  1. ライブラリプロジェクトのドキュメント
  2. リクエストモジュール
  3. テーブルモジュール
  4. 配列モジュール
  5. LINQのライブラリ標準クエリ演算子ライブラリ仕様
  6. 例としてHaskell言語を使用した機能的アプローチの利点に関する感動的なプレゼンテーション。



All Articles