ReasonML 签名不匹配

ReasonML Signature Mismatch

我在 ReasonML 中发现我定义的解析为 type mutationFunctionType = (~id: UUID.t, ~classroomId: UUID.t, unit) => unit; 的类型与我期望的 'a 之间的签名不匹配。 (见下文)。

[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 基本上可以被视为任何类型。

谢谢

类型多态性允许您以某些类型通用地编写函数。 例如,多态身份的类型为 'a => 'a。 这意味着它可以通过实例化 'a.

在类型 int => intbool => bool 上使用

然而,这'a并不意味着任何事情都会发生。它只在一个方向上起作用: 'a可以变成任何东西,但任何东西都不能变成'a。 所以从 ApolloMutation.apolloMutationType(Config.t) => 'a 你确实可以得到 ApolloMutation.apolloMutationType(Config.t) => mutationFunctionType但你做的恰恰相反

例如,您不能将 int => int 函数转换为 int => 'a 函数。 顺便说一下,提供这样一个 int => 'aApolloMutation.apolloMutationType(Config.t) => 'a 类型的函数是不可能的,除非它 returns 错误或不终止。因此,我建议尽可能更新您的签名以明确提及 mutationFunctionType.

I'm curious about why I'm receiving this error because I thought the polymorphic type `a could be treated as basically any type.

是的,你是对的,'a 意味着什么。但成为任何人究竟意味着什么?值的类型定义了可以在哪些上下文中使用该值。例如,如果您的值的类型为 int,那么它可以用在任何需要 int 或 ''a 的地方。说你的函数有类型 'a 意味着你的函数可以用来代替 intunit 或代替任何其他函数。实际上,“a”类型意味着可以使用此值代替任何其他值。

换句话说,你签名中的函数类型就是你的合约。并且您试图通过说您的功能可以适用于任何地方来过度约束自己。类型检查器说你不对——你的函数只适用于非常特定的上下文

ApolloMutation.apolloMutationType(Config.t) => mutationFunctionType

它甚至不是多态的(也就是说,你的函数不可能适合一种以上的类型 - 它是 单态的,即只有一种类型)。

然而,有一个特定的上下文,其中使用 'a 意味着 "I don't care, pick whatever type you want",这是当您指定 类型约束 时,即,当您在 let 绑定中注释函数的参数或变量时,例如,此处 'a

 let sum = (x, y): 'a => x + y;

表示 "whatever type",尽管它是 int,而且只是 int

当您提供注释(又名类型约束)时,类型检查器会将其添加为类型方程的附加约束,例如,

 let pair: ('a, 'a) => ('a, 'a) = (x, y) => (x, y);

这里,函数pair被限制为一对两个相等的(unifiable1)类型,但这些类型可以是任何类型,唯一重要的是他们是平等的。如果我们不添加这个约束,那么函数的类型将是 ('a,'b) => ('a,'b),这是更通用的。


1)其实并不要求它们相等,这样的约束只是说xy必须统一,通常,在单态类型的情况下,这意味着它们应该相等,例如,int 只能与 int 统一,但在多态类型的情况下,尤其是子类型,将推断出最小上限,但这是一个完全不同的故事。