Haskell数据结构模拟替代版本编号方法

时间:2017-07-17 18:14:32

标签: haskell version-numbering

我想在Haskell中模拟version numbering in more generic terms。我正在寻找一个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头痛。

1 个答案:

答案 0 :(得分:2)

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

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

versionToString = intercalate "." . map show . unLTRVersion

这允许任意版本的“x.y.z”形式用于任何数量的版本“块”。正确的排序关系是可导出的,这很方便。

(注意:人们可能认为自然数字会更准确,但Haskell会很乐意通过尝试从较小的数字中减去更大的数字来生成运行时失败,因此YMMV。Int是也可以在序曲中使用,而自然数则不是。)

要实施从右到左的版本控制方案,可以使用snoc列表或反向列表进行比较(使用comparing中的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,也可以在MayVersion上推导出ChunkComplex Mess

对于非常随意的版本控制概念(例如,可能涉及“@”或“。”之外的其他分隔符),versions包提供了一种有趣的称为VNL Nothing (VNR Nothing (VC (Just 1)) 的版本。满足。不过,它只会以特别的方式支持“虚构”版块。

我还应该提一下,将LTR和RTL cons单元组合成相同的列表结构似乎是不正确的构造,所以我没有考虑它。

是什么意思?
data Version
  = LTR LTRVersion
  | RTL RTLVersion

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

defaultJsch.AddIdentity( "<path>", "<passphrase>" )

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