替代版本编号方法的 Eq 定义
Eq definition for alternative version numbering approach
我正在尝试为 alternative version numbering approach 定义 Eq 运算符。
type VersionCompound = Maybe Int -- x, 0, 1, 2, ...
type VersionNumber = [VersionCompound] -- x.x, x.0, x.1, x.2, ... , 1.0, 1.1, 1.2, ... 1.x.x, 2.x.x, 3.x.x, ...
instance Eq VersionNumber where
[] == [] = True
(x:[]) == (y:[]) = x == y
(Nothing:xs) == ys = (xs == ys)
xs == (Nothing:ys) = (xs == ys)
对于以下情况,预计它 returns True
:x.x.x == x
、1.x.x == x.1.x.x
、x.1 == 1
等。但是它 returns 一个错误:
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
)列表。因此,例如,x.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
)。
修复错误 Overlapping instances for Eq [VersionCompound]
后我苦苦挣扎的是如何通过模式匹配获得 x.x.x == x
-> True
。但是,正如@WillemVanOnsem 出色地指出的那样,它不应该通过模式匹配来实现,而应该通过函数组合来实现。
PS. 我个人鼓励您为@WillemVanOnsem 的答案点赞,因为他的解决方案非常优雅,需要付出一些努力才能提出并代表本质Haskell 的力量。
您使用类型别名。这意味着你还没有定义一个单独的类型 VersionNumber
或 VersionCompound
;您只是构造了一个 别名 。在幕后,Haskell 将 VersionNumber
简单地视为 [Maybe Int]
。
现在如果我们查看 Haskell 的库,我们会看到:
instance Eq Int where
-- ...
instance Eq a => Eq (Maybe a) where
-- ...
instance Eq a => Eq [a] where
-- ...
这意味着 Eq Int
已定义,Eq (Maybe Int)
也已定义,因此 Eq [Maybe Int]
也由 Haskell 库定义。所以你实际上已经构造了一个 Eq VersionNumber
而没有写一个。现在您尝试编写一个额外的,当然,编译器会混淆选择哪个。
有一些方法可以解决重叠实例,但这可能只会产生更多的麻烦。
因此,您最好使用单个构造函数构造 data
类型。例如:
type VersionCompound = Maybe Int
<b>data</b> VersionNumber = <b>VersionNumber</b> [VersionCompound]
现在,由于只有一个构造函数,您最好使用 newtype
:
type VersionCompound = Maybe Int
<b>newtype</b> VersionNumber = VersionNumber [VersionCompound]
现在我们可以像这样定义我们的特殊实例:
instance Eq VersionNumber where
(<b>VersionNumber</b> a) == (<b>VersionNumber</b> b) = a <b>=*=</b> b
where [] =*= [] = True
(x:[]) =*= (y:[]) = x == y
(Nothing:xs) =*= ys = (xs =*= ys)
xs =*= (Nothing:ys) = (xs =*= ys)
因此我们解开构造函数,然后使用另一个本地定义的函数 =*=
,它的工作方式与您在问题中定义的一样。
但是请注意,您忘记了程序中的一些模式,例如左侧和右侧的 Just x : xs
。所以,你最好先解决这些问题。如果我 运行 你的代码通过编译器,我会收到以下警告:
Pattern match(es) are non-exhaustive
In an equation for ‘=*=’:
Patterns not matched:
[] (Just _:_)
[Just _] []
[Just _] (Just _:_:_)
(Just _:_:_) []
你想如何处理这些情况当然取决于你。 @DanielWagner 建议使用:
import Data.Function(on)
import Data.Maybe(catMaybes)
instance Eq VersionNumber where
(VersionNumber a) == (VersionNumber b) = on (==) catMaybes a b
这将过滤掉两个 VersionNumber
的 Nothing
值,然后检查 Just
中的值是否生成相同的列表。所以 3.x.2.x.x.1
将等于 3.2.1
和 x.x.x.x.x.3.2.1
.
编辑:根据您在评论中的说明,您可能正在寻找:
import Data.Function(on)
instance Eq VersionNumber where
(VersionNumber a) == (VersionNumber b) = on (==) (dropWhile (Nothing ==)) a b
我正在尝试为 alternative version numbering approach 定义 Eq 运算符。
type VersionCompound = Maybe Int -- x, 0, 1, 2, ...
type VersionNumber = [VersionCompound] -- x.x, x.0, x.1, x.2, ... , 1.0, 1.1, 1.2, ... 1.x.x, 2.x.x, 3.x.x, ...
instance Eq VersionNumber where
[] == [] = True
(x:[]) == (y:[]) = x == y
(Nothing:xs) == ys = (xs == ys)
xs == (Nothing:ys) = (xs == ys)
对于以下情况,预计它 returns True
:x.x.x == x
、1.x.x == x.1.x.x
、x.1 == 1
等。但是它 returns 一个错误:
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
)列表。因此,例如,x.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
)。
修复错误 Overlapping instances for Eq [VersionCompound]
后我苦苦挣扎的是如何通过模式匹配获得 x.x.x == x
-> True
。但是,正如@WillemVanOnsem 出色地指出的那样,它不应该通过模式匹配来实现,而应该通过函数组合来实现。
PS. 我个人鼓励您为@WillemVanOnsem 的答案点赞,因为他的解决方案非常优雅,需要付出一些努力才能提出并代表本质Haskell 的力量。
您使用类型别名。这意味着你还没有定义一个单独的类型 VersionNumber
或 VersionCompound
;您只是构造了一个 别名 。在幕后,Haskell 将 VersionNumber
简单地视为 [Maybe Int]
。
现在如果我们查看 Haskell 的库,我们会看到:
instance Eq Int where
-- ...
instance Eq a => Eq (Maybe a) where
-- ...
instance Eq a => Eq [a] where
-- ...
这意味着 Eq Int
已定义,Eq (Maybe Int)
也已定义,因此 Eq [Maybe Int]
也由 Haskell 库定义。所以你实际上已经构造了一个 Eq VersionNumber
而没有写一个。现在您尝试编写一个额外的,当然,编译器会混淆选择哪个。
有一些方法可以解决重叠实例,但这可能只会产生更多的麻烦。
因此,您最好使用单个构造函数构造 data
类型。例如:
type VersionCompound = Maybe Int
<b>data</b> VersionNumber = <b>VersionNumber</b> [VersionCompound]
现在,由于只有一个构造函数,您最好使用 newtype
:
type VersionCompound = Maybe Int
<b>newtype</b> VersionNumber = VersionNumber [VersionCompound]
现在我们可以像这样定义我们的特殊实例:
instance Eq VersionNumber where
(<b>VersionNumber</b> a) == (<b>VersionNumber</b> b) = a <b>=*=</b> b
where [] =*= [] = True
(x:[]) =*= (y:[]) = x == y
(Nothing:xs) =*= ys = (xs =*= ys)
xs =*= (Nothing:ys) = (xs =*= ys)
因此我们解开构造函数,然后使用另一个本地定义的函数 =*=
,它的工作方式与您在问题中定义的一样。
但是请注意,您忘记了程序中的一些模式,例如左侧和右侧的 Just x : xs
。所以,你最好先解决这些问题。如果我 运行 你的代码通过编译器,我会收到以下警告:
Pattern match(es) are non-exhaustive
In an equation for ‘=*=’:
Patterns not matched:
[] (Just _:_)
[Just _] []
[Just _] (Just _:_:_)
(Just _:_:_) []
你想如何处理这些情况当然取决于你。 @DanielWagner 建议使用:
import Data.Function(on)
import Data.Maybe(catMaybes)
instance Eq VersionNumber where
(VersionNumber a) == (VersionNumber b) = on (==) catMaybes a b
这将过滤掉两个 VersionNumber
的 Nothing
值,然后检查 Just
中的值是否生成相同的列表。所以 3.x.2.x.x.1
将等于 3.2.1
和 x.x.x.x.x.3.2.1
.
编辑:根据您在评论中的说明,您可能正在寻找:
import Data.Function(on)
instance Eq VersionNumber where
(VersionNumber a) == (VersionNumber b) = on (==) (dropWhile (Nothing ==)) a b