使用构造函数的一部分来导出Haskell数据中的实例

cha*_*ni2 1 compiler-construction haskell derived-instances

我需要为数据派生Eq,但对于某些构造函数,我想忽略一些字段.数据用于表示DataTypes(我们正在开发编译器):

data DataType
    = Int | Float | Bool | Char | Range | Type
    | String Width
    | Record (Lexeme Identifier) (Seq Field) Width
    | Union  (Lexeme Identifier) (Seq Field) Width
    | Array   (Lexeme DataType) (Lexeme Expression) Width
    | UserDef (Lexeme Identifier)
    | Void | TypeError
    deriving (Ord)
Run Code Online (Sandbox Code Playgroud)

我需要忽略它出现的每个contstructor中的Width 字段.

Don*_*art 8

如果要使用自定义Eq语义,则无法派生Eq.您必须手动编写实例.

一个常见的诀窍是:

  • 定义一个DataType',它删除你想要忽略的字段
  • 为此得出Eq
  • 将DataType的Eq定义为 a == b = toDataType' a == toDataType' b

这至少使它不那么特别,在它自己的类型中捕获不同的Eq语义,它可以/可以/派生.


Rei*_*ite 6

Don的另一种方法是使用包装器类型来编码特殊字段所需的实例:

newtype Metadata a = Metadata { unMetadata :: a }

instance Eq (Metadata a) where
    (==) _ _ = True

instance Ord (Metadata a) where
    compare _ _ = EQ
Run Code Online (Sandbox Code Playgroud)

然后,您可以Width将DataType定义中的所有内容替换为Metadata Width并派生实例.

data DataType
    = Int | Float | Bool | Char | Range | Type
    | String (Metadata Width)
    | Record (Lexeme Identifier) (Seq Field) (Metadata Width)
    | Union  (Lexeme Identifier) (Seq Field) (Metadata Width)
    | Array   (Lexeme DataType) (Lexeme Expression) (Metadata Width)
    | UserDef (Lexeme Identifier)
    | Void | TypeError
    deriving (Eq, Ord)
Run Code Online (Sandbox Code Playgroud)

此解决方案使您的DataType定义更加冗长(并且更明确?),但在使用这些Width值时需要包装和解包.

  • 这有一个很好的戒指:-) (2认同)