2017-12-18 107 views
4

给定某个数据类型的两个项t1 t2,是否有某种方法可以检查t1和t2是否以相同构造函数开始,而不在构造函数中进行穷举或模式匹配?就像如果我喜欢的类型要么是B,那么我想比较Haskell中两个项的构造函数的一般方法

checkConst (Left x) (Left y) = True 
checkConst (Right x) (Left y) = False 
... 

等实际上不这样做,模式匹配,并在某种程度上是普遍适用于其他类型的用10层构造的顺序。有没有一个很好的方法来做到这一点?

+0

也许你可以使用[镜头包]中的[Pri​​sms](https://hackage.haskell.org/package/lens-4.15.4/docs/Control-Lens-Prism.html)(https: //hackage.haskell.org/package/lens-4.15.4),可能值得一试。 –

回答

6

您可能正在寻找Data.Data模块中提供的泛型功能。如果你定义一个派生Data实例的数据类型,例如:

{-# LANGUAGE DeriveDataTypeable #-} 
import Data.Data 
data Foo = Bar1 Int 
     | Bar2 String String 
     | Bar3 Double 
     deriving (Data) 

那么你就可以toConstr检索一个值的构造:

> toConstr (Bar1 1) 
Bar1 
> toConstr (Bar2 "hello" "there") 
Bar2 
> 

这些都是可以Constr类型的值平等比较,这样你就可以定义:

checkConst :: (Data g) => g -> g -> Bool 
checkConst x y = toConstr x == toConstr y 

,并得到:

> checkConst (Bar1 10) (Bar1 20) 
True 
> checkConst (Bar1 10) (Bar3 20) 
False 
> 
3

您可以使用某种中间类型,它可以唯一地区分每个构造函数并具有一个Eq实例。例如,您可以使用Int来区分每个数据构造函数,然后比较这些值。

checkConst x y = toInt x == toInt y 
    where 
    toInt (Left _) = 1 :: Int 
    toInt (Right _) = 2 

如果你的类型实现了从Data.DataData,你可以使用toConstr使用Constr为您的中间类型。在Either的情况下,这不是必需的,因为您可以使用isRight x == isRight y,但对于具有10个构造函数的数据类型,这将更清晰。