问题
I have a very simple MergeSort implementation on List.
/// Divide the list into (almost) equal halves
let rec split = function
| [] -> [], []
| [x] -> [x], []
| x1::x2::xs -> let xs1, xs2 = split xs
x1::xs1, x2::xs2
/// Merge two sorted lists
let rec merge xs ys =
match xs, ys with
| [], _ -> ys
| _, [] -> xs
| x::xs', y::ys' when x <= y -> x::merge xs' ys
| _, y::ys' -> y::merge xs ys'
let rec mergeSort = function
| [] -> []
| xs -> let xs1, xs2 = split xs
merge (mergeSort xs1) (mergeSort xs2)
But whenever I tried to test with any input in F# Interactive:
let xs = mergeSort [1;4;3;2];;
I encountered a value restriction error:
error FS0030: Value restriction. The value 'xs' has been inferred to have generic type val xs : '_a list when '_a : comparison Either define 'xs' 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.
Why does it happen? What is a simple way to fix it?
回答1:
You are not handling the special case of 1-element lists in mergeSort
.
The general case is "too general" to infer the right type. As a consequence, the compiler infers a too generic type for the function ('a list -> 'b list) and the result is always a generic list (which is not allowed due to value restriction).
If you fix it like this, the type will be correctly inferred as 'a list -> 'a list.
let rec mergeSort = function
| [] -> []
| [x] -> [x]
| xs -> let xs1, xs2 = split xs
merge (mergeSort xs1) (mergeSort xs2)
来源:https://stackoverflow.com/questions/12671112/why-does-value-restriction-happen-with-mergesort-function