let rec merge = function
| ([], ys) -> ys
| (xs, []) -> xs
| (x::xs, y::ys) -> if x < y then x :: merge (xs, y::ys)
else y :: merge (x::xs, ys)
let rec split = function
| [] -> ([], [])
| [a] -> ([a], [])
| a::b::cs -> let (M,N) = split cs
(a::M, b::N)
let rec mergesort = function
| [] -> []
| L -> let (M, N) = split L
merge (mergesort M, mergesort N)
mergesort [5;3;2;1] // Will throw an error.
我从这里StackOverflow Question获取此代码但是当我使用列表运行mergesort时出现错误:
stdin(192,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : '_a list when '_a : comparison
我该如何解决这个问题?问题是什么?信息越多越好(所以我可以学习:))
答案 0 :(得分:3)
您的mergesort函数缺少导致签名由编译器推断为'a list -> 'b list
而不是'a list -> 'a list
的情况。它应该是'a list -> 'a list
的原因是你不打算在mergesort中更改列表的类型。
尝试将mergesort函数更改为此,以解决问题:
let rec mergesort = function
| [] -> []
| [a] -> [a]
| L -> let (M, N) = split L
merge (mergesort M, mergesort N)
您的代码的另一个问题是,merge和split都不是尾递归的,因此您将在大型列表上获得堆栈溢出异常(尝试调用更正的mergesort,如mergesort [for i in 1000000..-1..1 -> i]
)。
您可以使用累加器模式
使拆分和合并函数尾递归let split list =
let rec aux l acc1 acc2 =
match l with
| [] -> (acc1,acc2)
| [x] -> (x::acc1,acc2)
| x::y::tail ->
aux tail (x::acc1) (y::acc2)
aux list [] []
let merge l1 l2 =
let rec aux l1 l2 result =
match l1, l2 with
| [], [] -> result
| [], h :: t | h :: t, [] -> aux [] t (h :: result)
| h1 :: t1, h2 :: t2 ->
if h1 < h2 then aux t1 l2 (h1 :: result)
else aux l1 t2 (h2 :: result)
List.rev (aux l1 l2 [])
您可以阅读有关累加器模式here的更多信息;示例在lisp中,但它是一种通用模式,适用于提供尾调用优化的任何语言。