F#:算术运算符和多态性丢失(值限制?)

Posted

技术标签:

【中文标题】F#:算术运算符和多态性丢失(值限制?)【英文标题】:F#: arithmetic operator and loss of polymorphism (value restriction?) 【发布时间】:2014-12-25 07:24:19 【问题描述】:

此代码无法编译:

let f = fun x y -> x <<< y // bit shift
let g = fun x y -> x <<< y

[<EntryPoint>]
let main _ =
  printfn "%d" <| f 1 10
  printfn "%d" <| f 1L 10 // error
  printfn "%d" <| g 1L 10
  0
(7,21): error FS0001: This expression was expected to have type
    int
but here has type
    int64
http://ideone.com/qktsOb

我猜统一器在看到它们第一次出现时修复了与fg 关联的类型参数。是什么支配了这个过程?我认为这与“价值限制”非常相似,但 fg 已经 eta 扩展了!这是一个难题。

http://en.wikipedia.org/wiki/Value_restriction

我肯定会想象在整数类型上键入具有临时多态性的预定义运算符背后有一些黑魔法,但这只是我的猜测。任何信息表示赞赏。

【问题讨论】:

【参考方案1】:

通用数值编程是使用静态成员约束完成的,它不能在 .NET 类型系统中表示。它们仅存在于 F# 中,因此必须标记为 inline

你的代码可以这样写:

let inline f x y = x <<< y // bit shift
let inline g z y = z <<< y

[<EntryPoint>]
let main _ =
  printfn "%d" <| f 1 10
  printfn "%d" <| f 1L 10 // works too
  printfn "%d" <| g 1L 10
  0

MSDN 上的更多信息:Inline FunctionsStatically Resolved Type Parameters

【讨论】:

不知道我自己要花多长时间才能找到这些页面! 我想扩展这个答案,它实际上有两个部分:1)定义一个语法函数而不是右手边的 lambda 函数解决了值限制问题:let f x y = x &lt;&lt;&lt; y,和2)inline解决了算子约束问题。顺便说一句,System.Int32 并没有真正的静态成员 op_LeftShift。 F# 编译器隐式地用它来扩充类型,这进一步使类型推断复杂化。 @MarcSigrist 我认为let f x y = x &lt;&lt;&lt; y 只是let f = fun x y -&gt; x &lt;&lt;&lt; y 的语法糖。我只是不顾一切地想编译我的代码,所以我使用了最冗长的形式试图获得任何可能的线索。应该与部分申请表let f = (&lt;&lt;&lt;)进行比较,这应该是容易受到价值限制的。 @nodakai:在 F# 中,句法函数函数值 之间存在有意义的区别。只有语法函数可以内联。 @Daniel 你能指出我对句法函数和函数值之间区别的深入解释吗?【参考方案2】:

我认为这是 F# 自动泛化函数参数的方式。在第一次出现时,它推断函数 'f' 可能具有类型 ('a -> 'a -> 'a) 但第二次出现与此签名不匹配,因为它具有不同的签名 ('b -> 'a -> 'a) 因为它将 int64 和 int 视为不同的类型。

正如@Daniel 提到的,内联函数有时可以解决这个问题

可以在这里找到更多信息:http://msdn.microsoft.com/en-us/library/dd233183.aspx

有关静态成员约束的更多信息可以在 Tomas Petricek 的这篇文章中找到: http://tomasp.net/blog/fsharp-generic-numeric.aspx/

【讨论】:

"在第一次出现时,它推断函数 f 可能具有类型 ('a -&gt; 'a -&gt; 'a)" 我不认为 HM 是这样工作的。 HM 仅通过查看函数的定义(主体)来推断函数的最一般类型(通常是术语)。(在本例中为 ^a -&gt; int32 -&gt; ^a when ... 请注意我的问题与您引用的 MSDN 页面中的max 2.0 3 之间的区别。我的fg 本质上是相同的,所以当我的main 函数主体的第一行和第三行编译正常时,应该没有任何理由不编译第二行(除非.. . 涉及“静态方法”之类的复杂情况。)OTOH max 2.0 3 的问题仅仅是max 本身的定义不足以支持这种用法。 我会抽时间通读 Tomas 的文章。非常感谢您提供的宝贵信息!

以上是关于F#:算术运算符和多态性丢失(值限制?)的主要内容,如果未能解决你的问题,请参考以下文章

Java笔记(类型的转换标识符的命题规范算术运算符选择和循环语句)

js中的运算符和条件语句

算术和关系运算符

算术运算有哪些?逻辑运算有哪些?比较运算有哪些?

在python中有多少种运算符?解释一下算术运算符

使用任意定义的字符在基本N数字系统上进行算术运算