2

最後のパラメーターをジェネリック型として関数をカリー化しようとすると、コンパイラーはジェネリック型を最初に見つけた具体的な型に強制するため、スコープ内の後続の呼び出しのジェネリック プロパティが失われます。例:

type Bar =
    | String
    | Integer
    | Boolean

let foo (a: String)(b: 'm) =
    printfn "%A - %A" a b

let foobar (a: String)(bar: Bar) =
    let fooWithA= foo a
    match bar with
    | String -> fooWithA "String"
    | Integer -> fooWithA 42
    | Boolean -> fooWithA true

ここで、最後の 2 行で、関数が文字列を予期していることを示すコンパイラ エラーが表示されます。ただし、関数をヘルパー クラスでラップすると、次のように機能させることができます。

type FooHelper(a:String) =
    member this.foo (b: 'm) =
        printfn "%A - %A" a b

let foobar (a: String)(bar: Bar) =
    let fooHelperWithA= FooHelper a
    match bar with
    | String -> fooHelperWithA.foo "String"
    | Integer -> fooHelperWithA.foo 42
    | Boolean -> fooHelperWithA.foo true

それは私にコンパイラエラーを与えません。次に、関数を直接使用しようとすると、コンパイルエラーが再び発生します。

let foobar (a: String)(bar: Bar) =
    let fooHelperWithA= FooHelper(a).foo
    match bar with
    | String -> fooHelperWithA "String"
    | Integer -> fooHelperWithA 42
    | Boolean -> fooHelperWithA true

最後の 2 行でコンパイル エラーがスローされます。

これは意図した動作ですか、それともバグですか? これが機能する方法である場合、誰かが理由を説明できますか? これは私を本当に混乱させます。

4

1 に答える 1

4

したがって、これは古典的な値制限の問題です。次のコード ブロックを実行すると、より明確になります。

let foo (a: String)(b: 'm) =
    printfn "%A - %A" a b 
let fooWithA= foo  "hello"

これにより、次のエラーが発生します。

エラー FS0030: 値の制限。値 'fooWithA' は、ジェネリック型 val fooWithA を持つと推測されています: ('_a -> unit)
'fooWithA' への引数を明示的にするか、ジェネリックにするつもりがない場合は、型注釈を追加してください。

問題は、それfooWithAが適切な関数ではないため、ジェネリック型を持つことが許可されていないことです。

したがって、最初の例では、コンパイラは最初に文字列で呼び出していることを認識し、その特殊化を行いますが、整数とブール値の場合は失敗します。

2 番目の例では、汎用にできる関数を暗黙的に作成したので、すべて問題ありません。

3 番目の例では、最初の例と同じ問題があります。関数を値にバインドしているため、汎用にすることはできません。

これらすべてに対する最も簡単な解決策は、常にそのような関数を使用することです

let fooWithA a = foo "hello" a
于 2013-11-06T00:33:33.910 に答える