看一下这个 PureScript 代码:
type MyOtherProps = (value :: String)
type MyProps = (a :: String)
a
:: forall props phantom allProps
. Union MyProps MyOtherProps allProps
=> Union props phantom allProps
=> { | props }
-> Unit
a {} = unit
b = a { a: "hello", value: "apple" }
如果我尝试在
{}
上与任何不是 {}
的内容进行模式匹配,例如
a {value} = unit
然后我收到一个错误。为什么?
我试图让提供任何联合唱片公司成为可选,这样我就可以在不提供
a
或 a
标签的情况下拨打 value
。我知道,如果我在 a
的主体中使用变量,那么使用记录中的任何值都是不合理的,因为它们可能存在也可能不存在。但我不明白编译器如何知道是这种情况。我也知道这与编译器填写的phantom
类型的推断有关。但最终,allProps
的类型是明确定义的,所以我不明白为什么这种模式匹配理论上会失败,我在实践中知道原因。
您遇到的错误源于 PureScript 编译器如何推理类型推断和类型安全,特别是在行多态性和记录类型的上下文中。
在 PureScript 中,记录默认是打开的,这意味着它们可以包含其类型定义中未指定的其他字段。当您对函数定义中的记录进行模式匹配时,编译器会检查模式匹配是否涵盖了记录的所有可能字段。如果不存在,编译器将引发错误,以防止在您尝试访问提供的记录中不存在的字段时可能发生的潜在运行时错误。
让我们分解你的代码:
a
:: forall props phantom allProps
. Union MyProps MyOtherProps allProps
=> Union props phantom allProps
=> { | props }
-> Unit
a {} = unit
在此函数中
a
,您指定与空记录{}
匹配的参数模式。这意味着 a 期望收到没有字段的记录。但是,当您调用 a { a: "hello", value: "apple" }
时,您将传递带有两个字段 a
和 value
' 的记录,这与空记录的预期模式不匹配。因此,编译器会引发错误,因为模式匹配是
不完整。
如果您想让某些字段可选,可以使用行多态性来实现。您可以定义函数 a
来接受至少包含 MyProps 中指定的字段的任何记录,并且可以将 Record
类型与行变量结合使用来实现此目的。您可以通过以下方式修改代码来实现此目的:
a
:: forall props phantom allProps
. Union MyProps MyOtherProps allProps
=> Union props phantom allProps
=> Record (MyProps :: String | props)
-> Unit
a _ = unit
通过此修改,
a
将接受至少包含 MyProps
中指定的字段的任何记录,并且允许添加其他字段。这应该允许您在不提供所有字段的情况下调用 a
,使它们有效地可选。