在我的项目中,我创建了一个数据类型,它可以包含几种类型的值之一:
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)
使用on从Data.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一目了然更容易阅读.