17

F#の計算式の構文は次のとおりです。

ident { cexpr }

identビルダーオブジェクトはどこにありますか(この構文はDon Symeの2007年のブログエントリから取得されています)。

私が見たすべての例で、ビルダーオブジェクトはシングルトンインスタンスであり、起動するためにステートレスです。Donは、次のようなビルダーオブジェクトを定義する例を示していますattempt

let attempt = new AttemptBuilder()

私の質問:AttemptBuilder F#が計算式でクラスを直接使用しないのはなぜですか?確かに、この表記は、インスタンスメソッド呼び出しと同じくらい簡単に静的メソッド呼び出しに糖分を取り除くことができます。

インスタンス値を使用するということは、理論的には、同じクラスの複数のビルダーオブジェクトをインスタンス化できることを意味します。おそらく、何らかの方法でパラメーター化されているか、可変の内部状態でさえ(天国では禁止されています)。しかし、それがどのように役立つか想像できません。


更新:上記で引用した構文は、ビルダーが単一の識別子として表示される必要があることを示唆しています。これは誤解を招きやすく、おそらく以前のバージョンの言語を反映しています。最新のF#2.0言語仕様では、構文を次のように定義しています。

expr { comp-or-range-expr }

これにより、(ビルダーオブジェクトに評価される)任意の式を構成の最初の要素として使用できることが明確になります。

4

3 に答える 3

15

あなたの仮定は正しいです。ビルダーインスタンスはパラメーター化でき、パラメーターはその後計算全体で使用できます。

このパターンを使用して、特定の計算に対する数学的証明のツリーを構築します。各結論は、問題名計算結果、および基礎となる結論(見出語) のNツリーのトリプルです。

小さな例を示しましょう。プルーフツリーを削除しますが、問題名は保持します。より適切と思われるので、それを注釈と呼びましょう。

type AnnotationBuilder(name: string) =
    // Just ignore an original annotation upon binding
    member this.Bind<'T> (x, f) = x |> snd |> f
    member this.Return(a) = name, a

let annotated name = new AnnotationBuilder(name)

// Use
let ultimateAnswer = annotated "Ultimate Question of Life, the Universe, and Everything" {
    return 42
}
let result = annotated "My Favorite number" {
    // a long computation goes here
    // and you don't need to carry the annotation throughout the entire computation
    let! x = ultimateAnswer
    return x*10
}
于 2012-09-09T15:14:17.803 に答える
6

それは柔軟性の問題です。はい、Builderクラスを静的にする必要がある場合は簡単ですが、プロセスで多くを得ることがなくても、開発者からある程度の柔軟性が失われます。

たとえば、サーバーと通信するためのワークフローを作成するとします。コードのどこかで、そのサーバーのアドレス(Uri、IPAddressなど)を指定する必要があります。どの場合、単一のワークフロー内で複数のサーバーと通信する必要がありますか?答えが「none」の場合、さまざまな関数を介してその値を継続的に渡す代わりに、サーバーのUri/IPAddressを渡すことができるコンストラクターを使用してビルダーオブジェクトを作成する方が理にかなっています。内部的には、ビルダーオブジェクトがワークフローの各メソッドに値(サーバーのアドレス)を適用して、(正確ではありませんが)Readerモナドのようなものを作成する場合があります。

インスタンスベースのビルダーオブジェクトを使用すると、継承を使用して、いくつかの継承された機能を備えたビルダーの型階層を作成することもできます。私はまだ誰もこれを実際に行っているのを見たことがありませんが、繰り返しになりますが、静的に型付けされたビルダーオブジェクトでは得られない柔軟性があります。

于 2012-09-09T14:27:19.537 に答える
5

もう1つの方法は、次のように単一ケースの識別された共用体を使用することです。

type WorkFlow = WorkFlow with
    member __.Bind (m,f) = Option.bind f m
    member __.Return x = Some x

その後、あなたはそれを直接使用することができます

let x = WorkFlow{ ... }
于 2016-06-03T13:56:59.010 に答える