Haskell - 简单的构造函数比较(?)函数

nie*_*aki 21 haskell

在我的项目中,我创建了一个数据类型,它可以包含几种类型的值之一:

data PhpValue = VoidValue | IntValue Integer | BoolValue Bool
Run Code Online (Sandbox Code Playgroud)

我现在想做的是,有一个简单的方法来检查这个PhpValue类型的两个值是否是相同的构造函数(如果我在这里与术语混淆,请纠正我,但基本上我要检查两者是否是,例如,是IntValue,不关心特定的价值).

这是我为此写的一个函数:

sameConstructor :: PhpValue -> PhpValue -> Bool
sameConstructor VoidValue VoidValue = True
sameConstructor (IntValue _) (IntValue _) = True
sameConstructor (BoolValue _) (BoolValue _) = True
sameConstructor _ _ = False
Run Code Online (Sandbox Code Playgroud)

这应该工作,但我真的不喜欢它:如果我添加更多的构造函数(比如FloatValue Float),我将不得不重写函数,随着我的数据定义变大,它会变大.

问题:有没有办法编写这样的函数,以便在添加更多构造函数时它的实现不会改变?

为了记录:我不想改变data定义,我在其余的代码中有足够的Monads;)

Tik*_*vis 20

看看Data.Data它的toConstr功能.这将返回构造函数的表示形式,可以对其进行相等性比较.

使用扩展名(您可以放在{-# LANGUAGE DeriveDataTypeable #-}模块的顶部),您可以Data自动为您派生一个实例:

data PhpValue = VoidValue | IntValue Integer | BoolValue Bool 
              deriving (Typeable, Data)
Run Code Online (Sandbox Code Playgroud)

然后,您应该能够使用该toConstr函数通过构造函数进行比较.

现在以下将是真实的:

toConstr (BoolValue True) == toConstr (BoolValue False)
Run Code Online (Sandbox Code Playgroud)

使用onData.Function您现在可以改写sameConstructor到:

sameConstructor = (==) `on` toConstr
Run Code Online (Sandbox Code Playgroud)

这是一样的

sameConstructor l r = toConstr l == toConstr r
Run Code Online (Sandbox Code Playgroud)

我认为使用的版本on一目了然更容易阅读.


gee*_*aur 5

这被称为Haskell 和 ML 系列语言中的表达式问题;有许多不令人满意的解决方案(包括Data.Typeable在 Haskell 中使用和滥用类型类)但没有好的解决方案。