比较Haskell中两个术语的构造函数的一般方法

时间:2017-12-18 03:09:30

标签: haskell

鉴于某些数据类型的两个术语t1 t2,是否有某种方法可以检查t1和t2是否以相同的构造函数开头,而没有在构造函数上做一些详尽的情况或模式匹配?就像我的类型是一个b,然后我想要

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

等等,实际上没有进行模式匹配,并且可以推广到其他类型的10个构造函数。有没有一个很好的方法来做到这一点?

2 个答案:

答案 0 :(得分: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
>

答案 1 :(得分:3)

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

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

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