当参数为空列表时,List模块中的某些函数会失败。 List.rev就是一个例子。问题是可怕的价值限制。
我在尝试定义一个函数时遇到了同样的问题,该函数返回一个包含列表最后一个元素的列表:
let takeAllButLast (xs: 'a list) =
xs |> List.take (xs.Length - 1)
该函数适用于非空列表,但处理空列表的版本失败:
let takeAllButLast (xs: 'a list) =
if List.isEmpty xs then []
else xs |> List.take (xs.Length - 1)
takeAllButLast []
error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : '_a list, etc.
我尝试了几件事:使它成为内联函数,不指定参数的类型,指定返回值的类型,使函数依赖于类型参数,并使用Option类型以后获取中间结果转换为列表<' a>。没有任何效果。
例如,此功能具有相同的问题:
let takeAllButLast<'a> (xs: 'a list) =
let empty : 'a list = []
if List.isEmpty xs then empty
else xs |> List.take (xs.Length - 1)
之前在SO中提出了类似的问题:F# value restriction in empty list但是当参数为空列表时,唯一的答案也会失败。
有没有办法编写一个处理空列表和非空列表的函数?
注意:该问题并非特定于返回列表的最后一个元素的函数。
答案 0 :(得分:4)
功能本身完全没问题。该功能没有&#34;失败&#34;。
您无需修改函数体。这是对的。
问题仅在于您尝试调用该函数的方式:equals
。这里,编译器不知道结果应该具有什么类型。它应该是takeAllButLast []
吗?或者它应该是string list
?也许int list
?没有办法让编译器知道。所以它抱怨。
为了编译这样的调用,你需要帮助编译器:只需告诉它你期望得到什么类型。这可以从上下文中完成:
bool list
或者您可以直接声明调用表达式的类型:
// The compiler gleans the result type from the type of receiving variable `l`
let l: int list = takeAllButLast []
// Here, the compiler gleans the type from what function `f` expects:
let f (l: int list) = printfn "The list: %A" l
f (takeAllButLast [])
或者您可以声明函数的类型,然后调用它:
(takeAllButLast [] : int list)
您也可以分两步完成:
(takeAllButLast : int list -> int list) []
在每种情况下,原理都是相同的:编译器需要从某个地方知道 你期望的类型。
或者,您可以为其命名并将该名称设为 generic :
let takeAllButLast_Int : int list -> int list = takeAllButLast
takeAllButLast_Int []
这样的值可以像访问常规值一样被访问,但是在幕后它被编译为无参数的泛型函数,这意味着每次访问它都会导致执行它的正文。这就是let x<'a> = takeAllButLast [] : 'a list
和类似的&#34;通用值&#34;在标准库中实现。
但是,当然,如果你试图在F#互动中评估这样的价值,那么你将再次面对同样的问题 - 必须知道这种类型 - 而且你必须要解决它:<\ n \ n < / p>
List.empty