是否可以在 F# 中编写泛型函数,在其中指定类型“T”,但将“T”限制为类型“T2*”T3 的元组?
以下是我尝试过的一些只会产生编译器错误的事情:
let fun1<'T when 'T :> 'T2*'T3> () = …
let fun2<'T, 'T2, 'T3 when 'T :> 'T2*'T3> () = …
(在 fun2 中,“T2/”T3 最好由“T1”推断。)
我想这样做的原因是我正在编写一个带有内存数据库的应用程序,并且我正在尝试编写一个通用函数来提取与指定元组形式的数据库实体关联的数据.我有一个可行的解决方案,但有一些缺点:
let workingExtractEntity<'T> (id : EntityID) (db: Database) : EntityID*'T =
let t = db.GetEntityComponent id typeof<'T>
(id, t)
以及具有更多类型参数的类似函数:
let workingExtractEntity2<'T1, 'T2> (id : EntityID) (db: Database) : EntityID*'T1*'T2 = …
这种方法的主要问题是每次使用该函数时,您都必须手动输入通用参数并对其进行排序。我更希望能够指定单个元组类型,并结合常用元组类型的类型别名,如下所示:
//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
请注意,数据库中没有存储 Player 类型的对象,而只有构成 Player 的组件(即 Position 和 Health)存储在那里。 (任何具有与其关联的位置和健康的实体都可以表示为玩家。)
有什么办法可以达到这样的目的吗?
最佳答案
我做了一些研究,我想我已经找到了我自己问题的答案:
不幸的是,我想做的事情在 F# 中似乎是不可能的,并且很好地总结了原因 here由用户 Gus:
I'm afraid there is no way to add a subtype constraint to a generic type parameter based on another one in F#. They're always assumed to be equal, see the spec New constraints of the form type :> 'b are solved again as type = 'b.
这种限制在 C# 中不存在,这有时会使互操作很麻烦。有一个 issue在 F# 语言建议 github 页面上解决它。
换句话说,你不能这样写函数:
let foo<'T, 'U when 'T :> 'U> () = …
这意味着你也不能这样做:
let foo2<'T, 'T2, 'T3 when 'T :> Tuple<'T2, 'T3>> () = …
这基本上是我想要的,除了额外的类型推断,所以不用输入整个:
let callFoo2 = foo2<int*string, int, string> ()
你可以这样写,然后从 'T1 推断出 'T2 和 'T3:
let callFoo2Differently = foo2<int*string> ()
关于generics - 是否可以在 ‘T is constrained to be a tuple of type ' T2*'T3 处编写一个 genericFunction<'T>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65149034/