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我已经声明它一样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

(以下仅基于观察。)

如果您有一个函数obj -> 'a,则不会使用对该函数的调用来推断/解决其参数的类型。插图:

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

writeLineobj -> unit

let square x = 
  writeLine x
  x * x

在上面的函数x中被推断为int因为(*). 如果可以限制类型,obj则此函数将不起作用(xobj在使用之前推断出(*),这将导致错误:类型obj不支持运算符(*))。

我认为这种行为是一件好事。没有必要限制类型,obj因为每种类型都已经隐式转换为obj. 这使您的程序更通用,并提供与 .NET BCL 更好的互操作性。

简而言之,obj与类型推断无关(耶!)。

于 2012-02-23T15:46:12.510 回答
0

这对我来说似乎是一个意外的行为。可以使用更简单的函数来演示:

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

一种可能的解释可能是 F# 编译器允许您调用一个函数,该函数采用某种类型的参数和任何子类型的参数。因此,您可以foo "hi" (new A())在不显式转换A为的情况下调用obj(这在前一段时间是必需的)。

这种隐式转换可能意味着编译器实际上解释bar为这样的:

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

...因此它认为该论点是通用的。无论如何,这只是一个推测,因此您可以尝试将其作为错误报告发送给microsoft dot comfsbugs

于 2012-02-23T13:34:48.637 回答