Is it possible in F# to write a generic function where you specify a type 'T, but constrain 'T to be a tuple of type 'T2*'T3?
Here's a couple of things I've tried that just produces compiler errors:
let fun1<'T when 'T :> 'T2*'T3> () = …
let fun2<'T, 'T2, 'T3 when 'T :> 'T2*'T3> () = …
(In fun2 'T2/'T3 would ideally be inferred by 'T1.)
The reason I want to do this is that I'm writing an application with an in-memory database, and I'm trying to write a generic function which extracts data associated with a database-entity in the specified tuple-form. I have a solution that works, but has a few drawbacks:
let workingExtractEntity<'T> (id : EntityID) (db: Database) : EntityID*'T =
let t = db.GetEntityComponent id typeof<'T>
(id, t)
As well as similar functions with more type arguments:
let workingExtractEntity2<'T1, 'T2> (id : EntityID) (db: Database) : EntityID*'T1*'T2 = …
The main problem with this approach is that you have to manually type in and order the generic arguments every time you use the function. I would have preferred being able to specify a single tuple type instead, in combination with type aliases for commonly used tuple types, like so:
//Obviously won’t compile, but illustrates what I would like to do.
let extractEntity2<'T when 'T :> EntityID*'T2*'T3> id db : 'T =
let t2 = db.GetEntityComponent id typeof<'T2>
let t3 = db.GetEntityComponent id typeof<'T3>
(id, t2, t3)
type Player = EntityID*Position*Health
let extractPlayer id db : Player = extractEntity2<Player> id db
Note that no objects of type Player are stored in the database, but rather only the components that make up a Player, namely Position and Health, are stored there. (Any entity with a Position and Health associated with it could be represented as a Player.)
Is there any way to achieve something like this?