0

我正在尝试在 Haskell中以更通用的术语模拟版本编号。我正在寻找一个代表我自己定义的结构的 Haskell 数据结构(VersionNumberWithMaybe)。

data VersionCompoundWithMaybe = Maybe Int -- Just n: 0, 1, 2, 3 ...
                                          -- Nothing: x
maybeToString :: Maybe Int -> String
maybeToString (Just n) = (show n)
maybeToString Nothing = "x"

data VersionNumberWithMaybe = VC (Maybe Int)             -- VersionCompound: x, 0, 1, 2, 3 ...
                | VNL (Maybe Int) VersionNumberWithMaybe -- VersionNumberLeft: x.x, x.0, x.1, x.2, ... , 1.0, 1.1, 1.2, ... 1.x.x, 2.x.x, 3.x.x, ...
                | VNR VersionNumberWithMaybe (Maybe Int) -- VersionNumberRight: the same as above, only underlying structure is different for simple parsing pursposes: x.x, x.0, x.1, x.2, ... , 1.0, 1.1, 1.2, ... 1.x.x, 2.x.x, 3.x.x, ...
                deriving (Show)

versionNumberWithMaybeToString :: VersionNumberWithMaybe -> String
versionNumberWithMaybeToString (VNL vc vn) = (maybeToString vc) ++ "." ++ (versionNumberWithMaybeToString vn)
versionNumberWithMaybeToString (VNR vn vc) = (versionNumberWithMaybeToString vn) ++ "." ++ (maybeToString vc)
versionNumberWithMaybeToString (VC vc) = (maybeToString vc)

是否有类似的标准库实现可以将字符串解析为这种数据结构并在左右表示之间进行转换?我将不胜感激任何评论/想法。提前致谢!

PS。我需要VNLVNR选项,以便我可以按以下方式比较版本号:x.x.3== x.3== 3。我假设只有VNR版本可以用于此目的:

instance Eq VersionNumberWithMaybe where
    (VC vc1) == (VC vc2) = (vc1 == vc2)
    ( VNL vc1 vn1 ) == ( VNL vc2 vn2 ) = (vc1 == vc2 && vn1 == vn2)
    ( VNR vn1 vc1 ) == ( VNR vn2 vc2 ) = (vc1 == vc2 && vn1 == vn2)

    ( VNL _ (VC vc1) ) == ( VC vc2 ) = vc1 == vc2 
    ( VC vc1 ) == ( VNL _ (VC vc2)) = vc1 == vc2

    ( VNR _ vc1 ) == (VC vc2) = vc1 == vc2
    ( VC vc1 ) == (VNR _ vc2) = vc1 == vc2

鉴于 的这个定义Eq,以下比较将按预期正常工作:

VNR (VNR ( VC Nothing ) Nothing) (Just 3) == VNR (VC Nothing) (Just 3) -- x.x.3 == x.3 -> True
VNR (VC Nothing) (Just 3) == VC (Just 3) -- x.3 == 3 -> True

虽然VNL它不会按预期工作,因为它会允许进行这样的3.x.x == 3.x -> True比较

PS2。谢谢大家的意见。我开始重新思考我是否真的需要两者VNRVNL(而不仅仅是,例如,VNL)来实现我想要的。我正在评估哪种方法最好只留下一个并避免整个conversion_between_representations 头痛。

4

1 回答 1

2

为了表示定义为由句点分隔的整数序列的版本号,可以简单地使用整数列表,而不是实现自己的列表类型:

newtype LTRVersion = MkLTRVersion { unLTRVersion :: [Int] }
  deriving (Show, Eq, Ord)

versionToString = intercalate "." . map show . unLTRVersion

这允许任意数量的版本“块”的形式“xyz”的任意版本。正确的排序关系是可导出的,方便。

(注意:有人可能认为自然数会是一种更精确的表示,但 Haskell 很乐意允许您通过尝试从较小的数中减去较大的数来生成运行时失败,因此 YMMV.Int也可以在序言中使用,而自然数不是。)

要实现从右到左的版本控制方案,可以使用 snoc 列表或反转列表以进行比较(使用comparingfrom Data.Ord):

newtype RTLVersion = MkRTLVersion { unRTLVersion :: [Int] }

instance Ord RTLVersion where
  compare = comparing (reverse . unRTLVersion)

但是,两者都只允许整数版本号。更随意的是:

newtype Version = MkVersion [Either Int String]
  deriving (Show, Eq)

instance Ord Version

versionToString :: Version -> String

留给读者练习。

缺少“块”的版本号的另一种概括可以表示每个块可能存在:

newtype MayVersion = MkMayVersion [Maybe Int]

我不确定显示、等同或比较这些版本的语义是什么,所以我不会猜测实现。

Maybe Int替换为使用在问题域中有意义的名称的等效类型也可能很有用:

data Chunk = Imaginary | Known Int

newtype MayVersion = MkMayVersion [Chunk]

Eq也可以Ord通过MayVersionChunk.

对于极其任意的版本控制概念(例如,可能涉及“@”或除“.”以外的其他分隔符的概念),versions包提供了一种有趣的版本类型,称为 aComplex Mess可能就足够了。不过,它只会以特别的方式支持“虚构”版本块。

我还应该提到,将 LTR 和 RTL cons 单元组合到同一个列表结构中似乎在构造上是不正确的,所以我没有考虑它。是什么意思

VNL Nothing (VNR Nothing (VC (Just 1))

成为?RTL 和 LTR 的版本对我来说似乎是无效的。如果你想两者都有一个数据结构,你可以结合

data Version
  = LTR LTRVersion
  | RTL RTLVersion

这确保了两种版本类型在构造上都是正确的(嗯,不会阻止无限的版本号,但除此之外)。但是,我不清楚 LTR 版本和 RTL 版本应该如何相互比较,所以我不确定这是否真的需要。

于 2017-07-17T18:56:46.437 回答