F# 错误:"Either make the arguments to 'it' explicit or, if you do not intend for it to be generic, a



在F#交互式shelldotnet fsi中,我正在尝试像在Haskell、中一样测试flip功能

flip :: (a -> b -> c) -> b -> a -> c

> let flip = fun f -> fun a -> fun b -> f(b)(a);;
val flip: f: ('a -> 'b -> 'c) -> a: 'b -> b: 'a -> 'c

然后,研究内置管道操作员

> (|>);;
val it: ('a -> ('a -> 'b) -> 'b)

到目前为止还不错。

现在,

> flip (|>);;
flip (|>);;
^^^^^^^^^
/..... : error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it: (('_a -> '_b) -> '_a -> '_b)    
Either make the arguments to 'it' explicit or, if you do not intend for it to be generic, add a type annotation.

有人能解释一下F#类型系统中的这个错误是怎么回事吗?

对我来说,

val it: (('_a -> '_b) -> '_a -> '_b)实际上应该是预期的结果,我该如何解决这个问题?谢谢

我之前的回答解释了什么是值限制以及为什么会发生这种情况。但现在你的下一个问题是:好吧,我该怎么办?

正如错误消息本身所暗示的那样,有两种可能的方法:(1(为其提供显式参数;或者(2(如果不希望它是泛型的,则添加类型注释。

1.显式自变量

let flippedPipe x = flip (|>) x

尽管从逻辑上讲,这与let flippedPipe = flip (|>)相同,但从语法上讲,它现在是一个函数,而不是一个值。语法对于值限制来说很重要。

2.类型注释

let flippedPipe : (int -> int) -> int -> int = flip (|>)

这是因为该函数不再是泛型函数,因此不适用"值限制"。在许多情况下,这是一个理想的选择,但从您在这里使用的功能类型来看,我认为这不是您在这种情况下想要的。

3.显式类型参数

错误消息没有提到这一点,公平地说,它可以被视为选项(2(的变体。这个想法是,你可以给你的函数显式的类型参数如下:

let flippedPipe<'a, 'b> = flip (|>)

这使得值限制消失了,因为即使它在技术上仍然适用,添加类型参数的事实可能表明你知道自己在做什么,所以编译器会关闭。

然而,尽管乍一看这似乎有效,但它的做法是错误的。如果你看看这个函数的推断类型,你会看到:

val flippedPipe : (obj -> obj) -> obj  -> obj

发生这种情况是因为,即使添加了类型参数,也没有指定它们的确切位置。对于编译器所知道的,它们可能根本不被使用(也称为"幻影类型"(。

因此,为了使其正常工作,这应该是定义:

let flippedPipe<'a, 'b> : ('a -> 'b) -> 'a -> 'b = flip (|>)

相关内容

最新更新