为什么这句话给我一个类型不匹配错误,
let x = List.rev [] in (3::x, true::x);;
虽然这句话没有?
let x = [] in (3::x, true::x);;
我假设它是因为x在第一个语句中被赋予函数调用,而它只在第二个语句中给出一个空列表。但是,我不确定为什么第二个有效,第一个没有?任何帮助都感激不尽。谢谢!
答案 0 :(得分:3)
尝试以下方法:
let x = [] ;;
结果:val x : 'a list
。 F#知道x
是尚未知类型的列表。如果它有任何内容,其类型将是已知的。这非常有效。
但以下将不工作:
let x = List.rev [] ;;
结果:
错误FS0030:值限制。值'x'被推断为具有泛型类型
val x : '_a list
将'x'定义为一个简单的数据项,使其成为具有显式参数的函数,或者,如果您不打算将其作为泛型,则添加类型注释。
F#中的“价值限制”错误很难理解 - 为什么[]
不允许List.rev []
? - 但this article介绍了一些细节。从本质上讲,F#总是让人感到安全,使函数通用,但如果以下两个条件适用,它只能让值通用感觉安全:
let
右侧的表达式是纯值,例如它没有副作用,
和强> let
右侧的表达式是不可变。当表达式为[]
时,F#知道它是纯粹的,不可变的值,因此它可以使它成为通用的('a list
)。但是当表达式为someFunction []
时,F#编译器不知道someFunction
将要做什么。即使在这种情况下,我们知道List.rev
是标准库的一部分并且匹配这两种情况,F#编译器也不知道。在像Haskell这样完全纯粹的语言中,你可以从函数的类型签名中知道它是纯粹的,但F#是一种更实用的语言。所以F#采用保证安全的方法,并且不使List.rev []
通用的结果。
因此,当您编写let x = [] in (3::x, true::x)
时,[]
值是通用空列表,因此它可以成为int list
或{{1 }} 如所须。但是当你写bool list
时,F#不能使let x = List.rev [] in (3::x, true::x)
通用。它可以说“这是我还不知道的类型列表”,并等待类型变得清晰。然后,使用此列表的特定类型的第一个表达式(在本例中为List.rev []
)将“锁定”该列表的类型。即,F#不能认为这个列表是通用的,所以现在它已经发现这个空列表是3::x
s的空列表。然后,当您尝试将int
附加到空bool
时,这是一个错误。
如果您将元组翻转为int list
,那么类型错误也会“翻转”:它会指向true::x, 3::x
并找到bool list
。
所以这个答案的简短版本是:你正在达到F#值限制,即使这并不是很明显,因为你得到的错误根本没有提到价值限制。
有关价值限制的详细讨论,请参阅Understanding F# Value Restriction Errors,包括您通常看到它的最常见位置(部分应用的功能)。