Dax Fohl
Dax Fohl

Reputation: 10781

Possible to use a parameter like `id` generically in F#?

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

Answers (2)

MrD at KookerellaLtd
MrD at KookerellaLtd

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

Brian Berns
Brian Berns

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

Related Questions