【发布时间】:2016-11-18 22:48:13
【问题描述】:
我构建了一个函数,给定一个组合列表,返回两个列表:
let rec split2 l =
match l with
[] -> ([], [])
| (x, y)::ls -> let (xs, ys) =
split ls in (x::xs, y::ys);;
val split2 : l:('a * 'b) list -> 'a list * 'b list
lsts = [('a', 1); ('b', 2); ('c', 3); ('d', 4)]
split2 lsts;;
val it : int list * char list = ([1; 2; 3; 4], ['a'; 'b'; 'c'; 'd'])
现在,我将这个概念应用于更复杂的列表:
let l1 = [('a', 1, 'a'); ('b', 2, 'b'); ('c', 3, 'c'); ('d', 4, 'd')]
我使用的函数出现了类型问题,所以我构建了第二个。在这种情况下,我已经仔细定义了类型,但是当它应用于l1 时仍然返回错误,即使它编译。
let rec split3 (l:(char * int * char) list) =
match l with
[] -> ([], [], [])
| (x, y, z)::ls ->
let (xs, ys, zs) =
split3 ls in (xs, ys, zs);;
val split3 : l:(char * int * char) list -> 'a list * 'b list * 'c list
split3 l1;;
error FS0030: Value restriction. The value 'it' has been inferred to
have generic type val it : '_a list * '_b list * '_c list
Either define 'it' as a simple data term, make it a function with explicit
arguments or, if you do not intend for it to be generic, add a type annotation.
为什么,即使声明了类型,也需要进一步的类型注释?
【问题讨论】:
-
确实如此。这让我想到了第二个问题:第一个示例中的“两个元素”列表和第二个示例中的“三个元素”列表有什么区别?毕竟它们都是由字符和整数组成的。
-
对不起,我的第一条评论无关紧要。编译器无法推断函数的返回类型。您可以明确表示:
let rec split3 (l:(char * int * char) list) : (char list * int list * char list) = -
关于价值限制错误的更多信息,因为有时很难理解:blogs.msdn.microsoft.com/mulambda/2010/05/01/…
-
这些函数已经存在于核心 F# 库中;他们被称为
List.unzip和List.unzip3。