了解类型不匹配错误?

时间:2017-04-20 02:54:38

标签: f#

为什么这句话给我一个类型不匹配错误,

let x = List.rev [] in (3::x, true::x);; 

虽然这句话没有?

let x = [] in (3::x, true::x);;

我假设它是因为x在第一个语句中被赋予函数调用,而它只在第二个语句中给出一个空列表。但是,我不确定为什么第二个有效,第一个没有?任何帮助都感激不尽。谢谢!

1 个答案:

答案 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#总是让人感到安全,使函数通用,但如果以下两个条件适用,它只能让通用感觉安全:

  1. let右侧的表达式是值,例如它没有副作用,
  2. let右侧的表达式是不可变
  3. 当表达式为[]时,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,包括您通常看到它的最常见位置(部分应用的功能)。