【问题标题】:Value restriction: The type 'bar' has been inferred to have generic type值限制:类型“bar”已被推断为具有泛型类型
【发布时间】:2016-09-08 14:58:57
【问题描述】:

在下面的 sn-p 中,我不明白为什么我必须像函数 foo 那样编写 fg,以及为什么它不能像函数 bar 那样工作。

let f a b = a,b
let g (a : 'a) (b : 'a) = a

let (>!) f1 f2 =
    fun a b ->
        let (x,y) = f1 a b
        f2 x y

let foo = fun a b -> (f >! g) a b
let bar = f >! g

谁能向我解释一下,为什么bar 不起作用?鉴于 foo 也有泛型类型,这对我来说毫无意义。

【问题讨论】:

  • 您添加了一个限制,即 g 的参数具有相同的类型,而 f 接受两种不同的类型
  • @PanagiotisKanavos 没有g 的args 上的注释,推断的类型是'a -> 'b -> 'a。所以我不明白为什么会改变事情,因为现在是'a -> 'a -> 'a

标签: f#


【解决方案1】:

foo 是一个函数,而bar 是一个值。是的,它是一个函数类型的值,但仍然是一个值。那里有细微的差别。

F# 编译器可以“看到”foo 是一个函数,因为它在 let 之后看到了 fun ->

另一方面,您的bar 是一个真值——通过调用不同的函数(运算符>!)获得的结果。 F# 有一条规则(称为“值限制”)(在日常术语中)说值(与函数不同)不能具有泛型类型,除非显式指定泛型参数,从而有效地使其成为“类型函数”。 (比这要复杂一点,请阅读下面的链接以获取完整图片)

不过,这并不是 F# 特有的 - 其他非纯 ML 变体也有这个。 Here 是对 F# 规则的讨论,here's 是对 SML 的讨论。

【讨论】:

  • 这不是暗示出了什么问题吗?函数最终不是一等公民吗? >!的返回值是一个函数,正如foo的定义是一个函数。
  • 阅读我提供的链接。
  • 不过,简单来说,这不是函数是一流的问题,而是语法和定义的问题。还有其他类似的例子:模块中定义的函数与静态类中定义的函数不同,它们与本地上下文中定义的函数不同。另一个例子——即使函数是“值”,它们的通用性也不包括在内——即你不能在没有实例化的情况下传递一个通用函数。
  • 从提供的链接中,我终于明白了它的含义。 F# 不保证函数没有副作用并返回不可变对象。因此,编译器必须阻止它工作,否则会出现病态的情况,这确实不应该工作。这也向我解释了为什么相同的方法在 haskell 中有效,而在 F# (ML) 中无效。非常感谢您的见解。
猜你喜欢
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-04
  • 2018-05-15
  • 2019-09-17
相关资源
最近更新 更多