Reputation: 10781
Is it possible to have a parameter representing something like id
(something of type 'T -> 'T
) and use it generically?
i.e. in the below, I have id_like
that I'd like to be able to operate on objects of any type. However it appears that as soon as I operate on an object of a specific type, the compiler specializes id_like
and won't allow it to operate on anything else.
Below I get FS0064: This construct causes code to be less generic than indicated by the type annotations
when I operate on a
, and then a compile error when I try to operate on b
.
let f (id_like: 'T -> 'T) (a: int) (b: bool) =
let a1 = id_like a
let b1 = id_like b
a1, b1
let _ = f id 0 false
If not, is this just an artifact of using Hindley-Milner? Is HM "greedy" in the cases of parameters holding functions?
Upvotes: 1
Views: 199
Reputation: 2807
you can sidestep the issue by wrapping the function in an interface
type Id_Wrapper() =
member __.Apply<'a> (x: 'a) = id x
let g (id_like : Id_Wrapper) (a: int) (b: bool) =
let a1 = id_like.Apply a
let b1 = id_like.Apply b
a1, b1
the the type is inferred on each application of Apply, which can then be different types
this code does compile
Upvotes: 2
Reputation: 17153
Unfortunately, this is not allowed, because it would make type inference undecidable. The resulting language is equivalent to System F (polymorphic lambda calculus).
Instead, Hindley-Milner type systems provide "let-polymorphism": Only values bound in a let
construct are polymorphic:
let id x = x
in ... (id 3) ... (id "text") ...
The parameters in lambda abstractions (i.e. function definitions) are monomorphic.
Upvotes: 1