了解F#值限制错误

时间:2009-07-15 13:37:42

标签: f# type-inference value-restriction

我不明白F#中的价值限制是如何运作的。我已经阅读了wiki以及MSDN documentation中的解释。我不明白的是:

  1. 为什么,例如,这给了我一个价值限制错误(取自this问题):

    let toleq (e:float<_>) a b = (abs ( a - b ) ) < e
    

    但不是:

    let toleq e (a:float<_>) b = (abs ( a - b ) ) < e
    
  2. 这是概括的......

    let is_bigger a b = a < b
    

    但这不是(它被指定为int):

    let add a b = a + b
    
  3. 为什么带隐式参数的函数会生成值限制:

    这样:

    let item_count = List.fold (fun acc _ -> 1 + acc) 0
    

    vs this:

    let item_count l = List.fold (fun acc _ -> 1 + acc) 0 l
    

    (请注意,如果我在代码片段中使用此函数,则VR错误将消失,但该函数将被指定为我使用它的类型,并且我希望它被推广)

  4. 它是如何运作的?

    (我正在使用最新的F#,v1.9.6.16)

3 个答案:

答案 0 :(得分:18)

修改

更好/最近的信息在这里:Keeping partially applied function generic

(原文如下)

我认为这里务实的一点是不要试图深入理解这一点,而是要了解一些通过VR并继续工作的一般策略。这是一个“警察出局”的答案,但我不确定花时间了解F#类型系统的内部(在发布之间以不同的方式继续发生变化)。

我提倡的两个主要策略是这些。首先,如果您使用函数类型定义一个值(带箭头' - &gt;'的类型),那么通过执行eta-conversion确保它是一个语法函数:

// function that looks like a value, problem
let tupleList = List.map (fun x -> x,x)
// make it a syntactic function by adding argument to both sides
let tupleList l = List.map (fun x -> x,x) l

其次,如果您仍然遇到VR /泛化问题,请指定整个类型签名以说出您想要的内容(然后在F#允许的情况下“退回”):

// below has a problem...
let toleq (e:float<_>) a b = (abs ( a - b ) ) < e
// so be fully explicit, get it working...
let toleq<[<Measure>]'u> (e:float<'u>) (a:float<'u>) (b:float<'u>) : bool = 
    (abs ( a - b ) ) < e
// then can experiment with removing annotations one-by-one...
let toleq<[<Measure>]'u> e (a:float<'u>) b = (abs ( a - b ) ) < e

我认为这两种策略是最好的务实建议。也就是说,这是我尝试回答您的具体问题。

  1. 我不知道。

  2. '&GT;'是一个完全通用的函数('a - &gt;'a - &gt; bool),适用于所有类型,因此is_bigger概括。另一方面,'+'是一个'内联'函数,它适用于少数原始类型和某类其他类型;它只能在其他“内联”函数中推广,否则必须固定到特定类型(或默认为“int”)。 (ad-hoc多态的'内联'方法是F#中的数学运算符如何克服缺少“类型类”。)

  3. 这是我上面讨论的'句法功能'问题; '让我们编译成字段/属性,与函数不同,它们不能是通用的。因此,如果您希望它是通用的,请将其作为一个功能。 (另请参阅this question以了解此规则的另一个例外情况。)

答案 1 :(得分:5)

引入了价值限制来解决存在副作用时多态性的一些问题。 F#从OCaml继承了这一点,我相信所有ML变种都存在价值限制。除了您引用的链接外,您还可以阅读few more links。由于Haskell是纯粹的,因此不受此限制。

至于你的问题,我认为问题3确实与价值限制有关,而前两个则没有。

答案 2 :(得分:2)

没有人,包括F#团队成员,以任何有意义的方式知道这个问题的答案。

F#类型推理系统就像VB6语法一样,编译器定义了真理。

不幸,但确实如此。