Reputation: 4037
I built a simple function that, given a list, returns a list where the contiguous occurrences of an elements in the input are reduced to one.
let rec reduce l =
match l with
| [] -> []
| [x] -> [x]
| x::(y::_ as xs) -> if x = y then
reduce xs
else
x::(reduce xs)
# reduce [1;1;2;2;2;3;3;4;3;3;3];;
- : int list = [1;2;3;4;3].
# reduce [’a’;’a’;’a’;’b’];;
- : char list = [’a’; ’b’].
# reduce [];; // The case
- : ’a list = []
Everything work as expected, except for the empty list []
input. The complainer says error FS0030: Value restriction. I tried to get a better comprehension of the phenomena through the documentation, but I feel like I still do not possess the skills to get the point properly. Why a generic function does need the case with []
to be type specified? Could not the result []
being simply reported without type inference? And, finally, how the function should be structured, in order to menage such a case?
Upvotes: 1
Views: 59
Reputation: 243041
As John said in the comment, the problem is that []
does not give the compiler any hint about what the type of the list is - in all other cases, you know it's a list of characters of integers, but here, the type is not known.
You cannot run F# code that involves unknown generic types, so there is no way to run your code and get a generic list back - when running code, all types need to be fully specified.
You can provide a type annotation in a number of ways to fix the type:
reduce ([] : int list)
(reduce [] : int list)
(reduce:int list -> _) []
You could also wrap the call into another generic function, which compiles, because now the generic code is inside another generic function that requires a type in order to be used:
let foo () = reduce []
But now you have the same problem - you need to specify type when calling foo
, or the compiler needs to be able to infer it from context, e.g. if you write 1 :: foo()
Upvotes: 2