我在我定义的解析为我期望的type mutationFunctionType = (~id: UUID.t, ~classroomId: UUID.t, unit) => unit;
和'a
的类型之间在ReasonML中遇到签名不匹配的问题。 (如下所示)。
[1] Signature mismatch:
[1] ...
[1] Values do not match:
[1] let callMutationWithApollo:
[1] ApolloMutation.apolloMutationType(Config.t) => mutationFunctionType
[1] is not included in
[1] let callMutationWithApollo:
[1] ApolloMutation.apolloMutationType(Config.t) => 'a
我很好奇为什么会收到此错误,因为我认为多态类型`a基本上可以视为任何类型。
谢谢
答案 0 :(得分:3)
类型多态性允许您以某些类型通用地编写函数。
例如,多态身份具有类型'a => 'a
。
这意味着可以通过实例化int => int
在bool => bool
或'a
类型使用它。
但是,此'a
并不表示任何事情。它仅在一个方向上起作用:
'a
可以成为任何事物,但是任何事物都不能成为'a
。
因此,您确实可以从ApolloMutation.apolloMutationType(Config.t) => 'a
获得
ApolloMutation.apolloMutationType(Config.t) => mutationFunctionType
,但您所做的却恰恰相反。
例如,您不能将int => int
函数转换为int => 'a
函数。
顺便说一句,除非返回错误或不终止,否则实际上不可能提供类型int => 'a
或ApolloMutation.apolloMutationType(Config.t) => 'a
的功能。因此,我建议您尽可能更新签名,以明确提及mutationFunctionType
。
答案 1 :(得分:1)
我很好奇为什么会收到此错误,因为我认为多态类型`a基本上可以视为任何类型。
是的,你是对的,'a
意味着任何东西。但是成为什么到底意味着什么?值的类型定义了可以在哪个上下文中使用该值。例如,如果您的值的类型为int
,则可以在需要int
或''a
的任何地方使用它。说您的函数具有类型'a
意味着您可以使用函数代替int
和unit
或任何其他函数。实际上,类型“ a”表示可以使用该值代替任何其他值。
用不同的方式表示您的签名中的函数类型是您的合同。并且您通过说您的功能可以在任何地方使用来使自己过度负担。而且类型检查器说您不正确-您的函数仅适用于非常特殊的上下文
ApolloMutation.apolloMutationType(Config.t) => mutationFunctionType
它甚至不是多态的(即,您的函数不可能适合多种类型-它是 monomorphic ,即只有一种类型)。
但是,在一个特定的上下文中,使用'a
的意思是“我不在乎,选择所需的任何类型”,这是在您指定类型约束,即当您在let绑定中注释函数的参数或变量时,例如,这里'a
let sum = (x, y): 'a => x + y;
表示“任何类型”,尽管事实上它是int
并且只有int
。
当您提供注释(又称类型约束)时,它由typecheker添加为类型方程式的附加约束,例如
let pair: ('a, 'a) => ('a, 'a) = (x, y) => (x, y);
在这里,函数pair
被约束为两个相等的对(unifiable 1 )类型的对,但是这些类型可以是任何东西,只需要它们相等即可。如果我们不添加此约束,则函数的类型将为('a,'b) => ('a,'b)
,这是更通用的。
1)实际上,它们不必相等,这种约束只是说x
和y
必须统一,通常在单态类型的情况下这意味着它们应该相等,例如int
仅与int
不可兼而有之,但是对于多型类型,尤其是对于子类型,将推断出最小上限,但这是一个完全不同的故事。