As far a I can tell, F# doesn't have any support for existential types. So, I'm looking for another way to express my idea.
I've got a data structure and its contents can be interpreted in a number of different ways. In this particular example I'll suppose it can be viewed as an int or a real:
type Packed = (* something sensible *) unit
type PackedType = | PackedInt
| PackedReal
let undefined<'a> : 'a = failwith "undefined"
let unpackInt : Packed -> int = undefined
let unpackReal : Packed -> real = undefined
let packInt : int -> Packed = undefined
let packReal : real -> Packed = undefined
where real
is something meaningful, say:
type real = int * int
let addReal : real -> real -> real = undefined
Now, I need a function addPacked : PackedType -> Packed -> Packed -> Packed
. I'd like it to be general, that is:
type NumberOp = [forall t] { opPack : 't -> Packed; opUnpack : Packed -> 't; opAdd : 't -> 't -> 't }
let getNumberOp (t : PackedType) =
match t with
| PackedInt -> { opPack = packInt; opUnpack = unpackInt; opAdd = (+) }
| PackedReal -> { opPack = packReal; opUnpack = unpackReal; opAdd = addReal }
let addPacked (t : PackedType) (a : Packed) (b : Packed) =
let { opPack = pack; opUnpack = unpack; opAdd = add } = getNumberOp t
pack <| add (unpack a) (unpack b)
Here I ended up with NumberOp
being existetial. So I'm asking whether there is another way to express this. I can't alter Packed
, [un]pack*
functions and addPacked
's type.
I've found this answer. It states that there is a “well-known pattern”, but the text is difficult to read and I couldn't make it work.