3

let makeElem次のコードで値制限エラーが発生します。

let elemCreator (doc: XmlDocument) = 
    fun name (value: obj) ->
        let elem = doc.CreateElement(name)
        match value with
        | :? seq<#XmlNode> as childs -> 
            childs |> Seq.iter (fun c -> elem.AppendChild(c) |> ignore)
            elem
        | _ -> elem.Value <- value.ToString(); elem

let doc = new XmlDocument()
let makeElem = elemCreator doc

elemCreatorから返された無名関数にジェネリックパラメーターがない場合、なぜ値制限エラーが発生するのですか?

コンパイラーは、推定されたmakeElemのタイプはであると述べてい(string -> 'a -> XmlNode)ます。'aしかし、なぜ私がそれを宣言したかのように2番目のパラメーターを推測するのobjですか?

4

3 に答える 3

1

コンパイラの一般化と圧縮プロセスの結果として、これは「予想される」動作である可能性があります (この場合は残念ですが) 。トーマスの例を考えてみましょう:

let foo (s:string) (a:obj) = a

定義するなら

let bar a = foo "test" a

コンパイラはbar : 'a -> obj最初の引数の型を一般化するため、型を推測します。あなたの場合、あなたは同等のものを持っています

let bar = foo "test"

bar構文関数ではなく値も同様です。コンパイラは、値の制限が適用されることを除いて、本質的に同じ推論手順を実行します。makeElemこれは、型注釈で明示的に注釈を付ける (または構文関数にする)必要があることを意味するため、あなたの場合は残念です。

于 2012-02-23T15:15:56.283 に答える
0

これは私には予期しない動作のように見えます。より単純な関数を使用して実証できます。

let foo (s:string) (a:obj) = a
let bar = foo "bar"             // Value restriction

考えられる説明の 1 つとして、F# コンパイラでは、任意のサブタイプの引数を使用して、何らかのタイプのパラメーターを受け取る関数を呼び出すことができるということがあります。foo "hi" (new A())そのため、明示的にキャストAしなくても呼び出すことができますobj(以前は必要でした)。

barこの暗黙的なキャストは、コンパイラが実際に次のように解釈することを意味する可能性があります。

let bar a = foo "bar" (a :> obj)

...そして、引数が一般的であると考えます。いずれにせよ、これは推測に過ぎないので、これをバグ レポートとしてfsbugs at microsoft dot comに送信してみてください。

于 2012-02-23T13:34:48.637 に答える
0

(以下は観察のみに基づいています。)

function がある場合obj -> 'a、その関数の呼び出しは、その引数の型を推測/解決するために使用されません。実例:

let writeLine (arg: obj) = System.Console.WriteLine(arg)

writeLineobj -> unit

let square x = 
  writeLine x
  x * x

上記の関数では、 が原因であるxと推測されます。型が によって制約される可能性がある場合、この関数は機能しません (を使用する前のように推論され、次の行に沿ってエラーが発生します: type does not support operator )。int(*)objxobj(*)obj(*)

この振る舞いは良いことだと思います。objすべての型はすでに暗黙的に に変換可能であるため、型を as に制限する必要はありませんobj。これにより、プログラムをより汎用的にすることができ、.NET BCL との相互運用性が向上します。

要するに、obj型推論には関係ありません (イェイ!)。

于 2012-02-23T15:46:12.510 に答える