Dav*_*erk 20 f# type-inference value-restriction
我不明白F#中的价值限制是如何运作的.我已经阅读了wiki中的解释以及MSDN文档.我不明白的是:
例如,为什么这给了我一个价值限制错误(取自这个问题):
let toleq (e:float<_>) a b = (abs ( a - b ) ) < e
Run Code Online (Sandbox Code Playgroud)
但这不是:
let toleq e (a:float<_>) b = (abs ( a - b ) ) < e
Run Code Online (Sandbox Code Playgroud)这一点可以概括......
let is_bigger a b = a < b
Run Code Online (Sandbox Code Playgroud)
但这不是(它被指定为int):
let add a b = a + b
Run Code Online (Sandbox Code Playgroud)为什么带隐式参数的函数会生成值限制:
这个:
let item_count = List.fold (fun acc _ -> 1 + acc) 0
Run Code Online (Sandbox Code Playgroud)
对此:
let item_count l = List.fold (fun acc _ -> 1 + acc) 0 l
Run Code Online (Sandbox Code Playgroud)
(请注意,如果我在代码片段中使用此函数,则VR错误将消失,但是该函数将被指定为我使用它的类型,并且我希望它被推广)
它是如何工作的?
(我正在使用最新的F#,v1.9.6.16)
Bri*_*ian 18
编辑
更好/最近的信息在这里:保持部分应用功能通用
(原文如下)
我认为这里务实的一点是不要试图深入理解这一点,而是要了解一些通过VR的一般策略并继续你的工作.这是一个"警察出局"的答案,但我不确定花时间理解F#类型系统的内部(在发布之间以不同的方式继续发生变化).
我主张的两个主要策略是这些.首先,如果您使用函数类型定义一个值(带有箭头' - >'的类型),那么通过执行eta转换确保它是一个语法函数:
// 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
Run Code Online (Sandbox Code Playgroud)
其次,如果你仍然遇到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
Run Code Online (Sandbox Code Playgroud)
我认为这两种策略是最好的实用建议.也就是说,这是我尝试回答您的具体问题.
我不知道.
'>'是一个完全通用的函数('a - >'a - > bool),适用于所有类型,因此is_bigger概括.另一方面,'+'是一个'内联'函数,它适用于少数原始类型和某类其他类型; 它只能在其他"内联"函数中推广,否则必须固定到特定类型(或默认为"int").(ad-hoc多态的'内联'方法是F#中的数学运算符如何克服缺少"类型类".)
这是我上面讨论的'句法功能'问题; '让我们编译成字段/属性,与函数不同,它们不能是通用的.因此,如果您希望它是通用的,请将其作为一个功能.(另请参阅此问题,以了解此规则的另一个例外情况.)
归档时间: |
|
查看次数: |
3582 次 |
最近记录: |