type Interpreter<'a> =
| RegularInterpreter of (int -> 'a)
| StringInterpreter of (string -> 'a)
let add<'a> (x: 'a) (y: 'a) (in_: Interpreter<'a>): 'a =
match in_ with
| RegularInterpreter r ->
x+y |> r
| StringInterpreter r ->
sprintf "(%s + %s)" x y |> r
The error message of it not being able to resolve 'a
at compile time is pretty clear to me. I am guessing that the answer to the question of whether it is possible to make the above work is no, short of adding functions directly into the datatype. But then I might as well use an interface, or get rid of generic parameters entirely.
Edit: Mark's reply does in fact do what I asked, but let me extend the question as I did not explain it adequately. What I am trying to do is do with the technique above is imitate what what was done in this post. The motivation for this is to avoid inlined functions as they have poor composability - they can't be passed as lambdas without having their generic arguments specialized.
I was hoping that I might be able to work around it by passing an union type with a generic argument into a closure, but...
type Interpreter<'a> =
| RegularInterpreter of (int -> 'a)
| StringInterpreter of (string -> 'a)
let val_ x in_ =
match in_ with
| RegularInterpreter r -> r x
| StringInterpreter r -> r (string x)
let inline add x y in_ =
match in_ with
| RegularInterpreter r ->
x in_ + y in_ |> r
| StringInterpreter r ->
sprintf "(%A + %A)" (x in_) (y in_) |> r
let inline mult x y in_ =
match in_ with
| RegularInterpreter r ->
x in_ * y in_ |> r
| StringInterpreter r ->
sprintf "(%A * %A)" (x in_) (y in_) |> r
let inline r2 in_ = add (val_ 1) (val_ 3) in_
r2 (RegularInterpreter id)
r2 (StringInterpreter id) // Type error.
This last line gives a type error. Is there a way around this? Though I'd prefer the functions to not be inlined due to the limits they place on composability.
The compiler ends up defaulting to int, and the kind of polymorphism you want is difficult to achieve in F#. This article articulates the point.
Perhaps, you could work the dark arts using
FSharp.Interop.Dynamic
but you lose compile time checking which sort of defeats the point.