web-dev-qa-db-ja.com

変更要求オブジェクトを使用した関数型プログラミング

以下はJavaScriptコードを使用していますが、F#は関数型プログラマーからの入力用にタグ付けされています。

関数型プログラミングでは、状態や受信パラメーターを変更すべきではないことを理解していますが、関数型プログラミングに関しては、正式なリクエストパターンについて混乱しています。

正式リクエストパターンは、同じオブジェクト内に入力パラメータと出力パラメータの両方を持つオブジェクトで構成されます。

この関数は、入力パラメーターの関連するサブセットを検索し、関連する結果フィールドに入力します。その後、リクエストオブジェクトは他のオブジェクトに渡され、そこで各関数が結果を更新または修飾して、パイプラインを形成します。

つまり、リクエストオブジェクトはパイプラインを通過するときに入力され、後続の各関数は前の操作の結果に依存します。

たとえば、次のJavaScriptコードのコンテキストで。

var request = {
    publicationId: "1234",
    permissions: [] // string array
    schema: null
    // a lot more other input and output params
}

次の関数はpublicationIdを読み取り、permissionsを更新します

authorization.requestPermissions(request);

次の関数は、publicationIdpermissions(前の呼び出しから)を読み取り、schemaに入力します

article.create(request);
article.upload(request); // uses updated schema from `article.create`
article.publish(request); // uses update schema from `article.upload`

後続のすべての操作は、前の操作の結果に依存します。

ここではpermissionsschemaの両方が出力されます

console.log(request.permissions)
console.log(request.schema)

問題は、関数型プログラミングに違反しているかどうかです。

このコードで何を変更すれば、フォーマルリクエストパターンをより機能的なプログラミングに準拠させることができますか?.

4
Devyiweid

このパターンは、関数型プログラミングでは許容できるパターンとは見なされません。実際、pure関数型プログラミング言語では、あなたが説明するように実装するのはかなり難しいでしょう。

関数形式の入力要求に対するプロセッサのパイプラインを生成するには、入力で要求を受け入れ、変更された要求を出力として返す関数を使用します。また、静的型付けを使用して、それらに依存する関数が呼び出される前に必要な更新が実行されていることを確認することも一般的です。 Haskellでは、あなたの例はおそらく次のようなものになるでしょう:

data Publication = Publication Int
data PublicationPerm = PublicationPerm Int [String]
data PublicationPermSchema = PublicationPermSchema Int [String] Schema

requestPermissions :: Publication -> PublicationPerm
requestPermissions (Publication id) = PublicationPerm id perms
       where perms = ... whatever code is needed to calculate permissions ...

createArticle :: PublicationPerm -> PublicationPermSchema
createArticle (PublicationPerm id perms) = PublicationPermSchema id perms schema
       where schema = ... whatever code is needed to calculate schema ...

logArticle :: PublicationPermSchema -> IO PublicationPermSchema
logArticle (PublicationPermSchema id perms schema) = do
        writeLogLine perms
        writeLogLine schema
        return (PublicationPermSchema id perms schema)

pipeline :: Publication -> IO PublicationPermSchema
pipeline = requestPermissions >>> createArticle >>> logArticle

各関数は入力を受け取り、計算した追加情報も含む新しいオブジェクトを返すことに注意してください。最後のパイプラインは、各関数を結合して、すべてのアクションを実行する結合された関数にします。

JavaScriptへの変換は、パイプラインが必要な情報を正しい順序で生成するという静的な保証を失いますが、実行することはできます。次のようになります。

requestPermisions = pub => ({ id: pub.id; perms: ... calculate permissions here ... })
createArticle = pub => ({ id: pub.id; perms: pub.perms; schema: ... })
logArticle = pub => { console.log (pub.perms); console.log (pub.schema); return pub; }
pipeline = pub => logArticle(createArticle(requestPermissions(pub)))
0
Jules