Haskell 替代版本编号方法的Eq定义

Haskell 替代版本编号方法的Eq定义,haskell,version-numbering,Haskell,Version Numbering,我正在尝试为定义Eq运算符 对于以下情况,它将返回True:x.x.x==x,1.x.x==x.1.x.x,x.1==1,等等,但它会返回一个错误: VersionNumber.hs:58:34: Overlapping instances for Eq [VersionCompound] arising from a use of ‘==’ Matching instances: instance Eq a => Eq [a] -- Defined

我正在尝试为定义Eq运算符

对于以下情况,它将返回
True
x.x.x==x
1.x.x==x.1.x.x
x.1==1
,等等,但它会返回一个错误:

VersionNumber.hs:58:34:
    Overlapping instances for Eq [VersionCompound]
      arising from a use of ‘==’
    Matching instances:
      instance Eq a => Eq [a] -- Defined in ‘GHC.Classes’
      instance Eq VersionNumber -- Defined at VersionNumber.hs:55:10
    In the expression: (xs == ys)
    In an equation for ‘==’: (Nothing : xs) == ys = (xs == ys)
    In the instance declaration for ‘Eq VersionNumber’
有没有办法解决这个问题


编辑:我通过对列表进行模式匹配来解决这个问题的方法被证明是不完整的。我想忽略给定版本左侧的任意
x
(或
Nothing
s)列表。因此,例如,
x.x.x.x
将等于
x.x.x
x
。类似地,
x.x.x.1
将等于
x.x.1
1
。如果中间有<代码> x <代码>,它就不会被扔掉。因此,对于这种情况,
x.x.1.x.0
将等于
x.1.x.0
1.x.0
。还有一个例子:
x.1.x.x.0.x
等于
1.x.x.0.x
x.1.x.0.x
等于
1.x.0.x
(只需删除左侧的
x

在修复Eq[VersionCompound]的一个错误
重叠实例后,我一直在努力解决的问题是如何通过模式匹配获得
x.x.x==x
->
True
。但是,正如@WillemVanOnsem精辟指出的,它不应该通过模式匹配来实现,而应该通过函数组合来实现

PS.我个人鼓励您投票支持@WillemVanOnsem的答案,因为他的解决方案非常优雅,需要一些努力才能得出,并且代表了Haskell power的精髓

使用类型别名。这意味着您尚未定义单独的类型
VersionNumber
VersionCompound
;您只是构造了一个别名。在窗帘后面,哈斯克尔看到的
VersionNumber
只是
[可能是Int]

现在,如果我们看看Haskell的图书馆,我们会发现:

instance Eq Int where
    -- ...

instance Eq a => Eq (Maybe a) where
    -- ...

instance Eq a => Eq [a] where
    -- ...
这意味着定义了
Eq Int
,也定义了
Eq(可能Int)
,因此Haskell库也定义了
Eq[可能Int]
。因此,实际上您已经构建了一个
Eq VersionNumber
,而没有编写它。现在您尝试编写一个附加的,当然,编译器会对选择哪一个感到困惑

有办法解决重叠实例,但这可能只会产生更多的麻烦

因此,最好使用单个构造函数构造
数据
类型。例如:

type VersionCompound = Maybe Int
data VersionNumber = VersionNumber [VersionCompound]
现在我们可以定义我们的特殊实例,如:

instance Eq VersionNumber where
    (VersionNumber a) == (VersionNumber b) = a =*= b
        where [] =*= [] = True
              (x:[]) =*= (y:[]) = x == y
              (Nothing:xs) =*= ys = (xs =*= ys)
              xs =*= (Nothing:ys) = (xs =*= ys)
你想如何处理这些案件当然取决于你@DanielWagner建议使用:

import Data.Function(on)
import Data.Maybe(catMaybes)

instance Eq VersionNumber where
    (VersionNumber a) == (VersionNumber b) = on (==) catMaybes a b
这将过滤掉
VersionNumber
s的
Nothing
值,然后检查
Just
中的值是否生成相同的列表。因此
3.x.2.x.x.1
将等于
3.2.1
x.x.x.x.3.2.1

编辑:根据您在评论中的说明,您可能正在寻找:

import Data.Function(on)

instance Eq VersionNumber where
    (VersionNumber a) == (VersionNumber b) = on (==) (dropWhile (Nothing ==)) a b

但是
VersionNumber
是一个类型别名…如果我执行
data VersionNumber=[VersionCompound]派生(Show,Eq)
,它会导致另一个错误:
无法解析数据/newtype声明中的数据构造函数:[VersionCompound]
您应该使用
data VersionNumber=VersionNumber[VersionCompound]
带构造函数。@关于基本语法错误,请参见.catMaybes
@Willem Van Onsem上的语法部分。我很感激上次编辑的
catMaybes
,但这并不是我想要实现的。我想忽略给定版本左侧的任意
x
s(或
Nothing
s)列表。因此,例如,
x.x.x.x
将等于
x.x.x
x
。同样地,
x.x.x.1
将等于
x.x.1
1
。如果中间有<代码> x <代码>,它就不会被扔掉。因此,对于这种情况,
x.x.1.x.0
将等于
x.1.x.0
1.x.0
。阅读您的答案后,我仍在努力解决的问题是如何通过模式匹配获得
x.x.x=*=x
->
True
。@altern:
x.1.x.x.0.x
是否等于
x.1.x.0.x
?目前,当两个版本相同时,我仍然难以理解规范。
x.1.x.x.0.x
等于
1.x.x.0.x
x.1.x.0.x
等于
1.x.0.x
。您只需删除左侧的
x
。@altern:我提出了一个符合您规范的实现(我想)。
Pattern match(es) are non-exhaustive
In an equation for ‘=*=’:
    Patterns not matched:
        [] (Just _:_)
        [Just _] []
        [Just _] (Just _:_:_)
        (Just _:_:_) []
import Data.Function(on)
import Data.Maybe(catMaybes)

instance Eq VersionNumber where
    (VersionNumber a) == (VersionNumber b) = on (==) catMaybes a b
import Data.Function(on)

instance Eq VersionNumber where
    (VersionNumber a) == (VersionNumber b) = on (==) (dropWhile (Nothing ==)) a b