Search code examples
f#polymorphismvalue-restriction

Value restriction - The value has been inferred to have generic type


Give the following definition

let fn (id: int) (_:string) = id

I can create a partially applied function

let fnPartial = fn 1

However changing the type of _ to a non sealed type like IEnumerable

let fn (id: int) (_:IEnumerable) = id

Causes a compilation error

Value restriction. The value 'fnPartial' has been inferred to have generic type val fnPartial : ('_a -> int) when '_a :> IEnumerable Either make the arguments to 'fnPartial' explicit or, if you do not intend for it to be generic, add a type annotation. (using built-in F# compiler)

A bug was raised but closed with the following response

Yes this is by design - IEnumerable is not sealed where string is, and this causes the value restriction to trigger

The work around is to add a type annotation

let fn (id: int) (_:IEnumerable ) = id
let fnPartial<'a> = fn 1

Can someone explain

  1. Whats the crux of the issue
  2. How does adding a type annotation fix the issue

Solution

  • The key is that values are not allowed to be generic in F#. When you partially apply a function the result is a value.

    In order to make the left hand side of a binding (or assignment) a function, you must define a parameter on the left hand side.

    The error you're getting is a result of IEnumerable not being specific enough for the value to be completely defined. Given IEnumerable you do not know what you're iterating over, and therefore the compiler cannot determine a proper type for the value.

    The answers to your question then are as follows:

    1. The crux is the issue is that a value cannot be generic
    2. Adding the type definition lets the compiler know that this is not a value, but rather is a function, or something which is allowed to be generic.

    Here is the relevant MSDN Docs: https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/dd233183(v=vs.100)#value-restriction