如何为自定义类型推导Eq类型类?编译报错问题咨询
这个问题我之前踩过坑!原因其实很简单——你用type定义的是类型别名,而PureScript的derive指令只能作用于真正的代数数据类型(也就是用data或newtype声明的类型),没法直接给类型别名推导实例。
为什么会报错?
type Entry = { firstName :: String , lastName :: String , address :: Address }这种写法只是给那个复杂的记录类型起了个“外号”,并没有创建新的类型构造器。当编译器处理derive instance eqEntry :: Eq Entry时,它会去寻找一个名为Entry的独立类型构造器,但类型别名并没有生成这个构造器,所以才会抛出Cannot derive a type class instance, because the type declaration for Entry could not be found的错误。
两种解决方案
方案1:改用newtype包装记录(推荐)
newtype是PureScript里零开销的类型包装器,它会创建一个独立的类型构造器,同时编译后和原记录类型完全一样。这样你就可以正常使用derive指令了:
newtype Address = Address { street :: String , city :: String , state :: String } newtype Entry = Entry { firstName :: String , lastName :: String , address :: Address } derive instance eqAddress :: Eq Address derive instance eqEntry :: Eq Entry
使用的时候只需要用构造器包裹/解包记录,比如Entry { firstName: "Alice", ... }或者通过模式匹配取出内部记录。
方案2:直接利用类型别名的底层实例(无需derive)
如果你不想额外包装类型,其实根本不需要写derive语句——PureScript会自动为所有字段都实现了对应类型类的记录类型生成实例。因为Entry只是记录类型的别名,底层记录类型已经拥有Eq实例(所有字段都是String或Address,而Address也是记录类型,字段都是String,都有Eq实例),所以你可以直接使用==比较Entry类型的值:
type Address = { street :: String , city :: String , state :: String } type Entry = { firstName :: String , lastName :: String , address :: Address } -- 直接使用==比较,无需手动derive compareEntries :: Boolean compareEntries = { firstName: "Bob", lastName: "Jones", address: { street: "456 Ave", city: "LA", state: "CA" } } == { firstName: "Bob", lastName: "Jones", address: { street: "456 Ave", city: "LA", state: "CA" } }
内容的提问来源于stack exchange,提问作者therewillbecode

