根据数据的特定部分派生实例

时间:2014-03-12 22:02:52

标签: haskell

我有以下代码

type Position = (Int,Int)

data CheckError where
    LError :: Position -> LexerError  -> CheckError
    PError :: Position -> ParseError  -> CheckError
    SError :: Position -> StaticError -> CheckError

我需要它来实例Ord,只需比较每个构造函数中的Position字段。

我得到了它的工作:

data CheckError where
    LError :: Position -> LexerError  -> CheckError
    PError :: Position -> ParseError  -> CheckError
    SError :: Position -> StaticError -> CheckError
    deriving (Show)

instance Eq CheckError where
    (LError l _) == (LError r _) = l == r
    (LError l _) == (PError r _) = l == r
    (LError l _) == (SError r _) = l == r
    (PError l _) == (LError r _) = l == r
    (PError l _) == (PError r _) = l == r
    (PError l _) == (SError r _) = l == r
    (SError l _) == (LError r _) = l == r
    (SError l _) == (PError r _) = l == r
    (SError l _) == (SError r _) = l == r

instance Ord CheckError where
    compare (LError l _) (LError r _) = l `compare` r
    compare (LError l _) (PError r _) = l `compare` r
    compare (LError l _) (SError r _) = l `compare` r
    compare (PError l _) (LError r _) = l `compare` r
    compare (PError l _) (PError r _) = l `compare` r
    compare (PError l _) (SError r _) = l `compare` r
    compare (SError l _) (LError r _) = l `compare` r
    compare (SError l _) (PError r _) = l `compare` r
    compare (SError l _) (SError r _) = l `compare` r

但我觉得这段代码太重复了。有没有办法告诉Haskell直接与Position字段进行比较?

2 个答案:

答案 0 :(得分:7)

也许这样?

 instance Eq CheckError where
    a == b = pos a == pos b 
              where 
                pos (LError p _) = p
                pos (PError p _) = p
                pos (SError p _) = p

答案 1 :(得分:3)

我建议使用来自on的{​​{1}}组合器稍微清洁一点:

Data.Function

其中import Data.Function instance Eq CheckError where (==) = (==) `on` pos instance Ord CheckError where compare = compare `on` pos 被定义为简单函数或记录字段(由@Xavier建议)。这可以简单地解读为“pos的比较是对他们立场的比较”。