我最近正在尝试将ADT重构为向后兼容的集合表示:
data Tag = TagFoo | TagBar !Text | TagBaz !Int ... -- many more
deriving (Eq, Generic, Ord, Show)
newtype Label = Label (HashSet Tag)
deriving (Eq, Generic, Show)为此,我定义了几个模式同义词,其效果如下:
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
pattern Foo :: Label
pattern Foo <- Tags [TagFoo] where
Foo = Label $ HashSet.singleton TagFoo
-- (let's say a lone TagBar is invalid)
pattern FooWithBar :: Text -> Label
pattern FooWithBar b <- Tags [TagFoo, TagBar b] where
FooWithBar b = Label $ HashSet.fromList [TagFoo, TagBar b]Tags模式定义为:
pattern Tags :: [Tag] -> Label
pattern Tags ts <- ((\(Label ts') -> sort $ HashSet.toList ts') -> ts)不幸的是,这个表单很容易出错,因为它要求用户在正确的Order中提供[Tag]列表。否则,像Tags [TagBar "x", TagFoo]这样的模式将不会与Label $ HashSet.fromList [TagBar "x", TagFoo]匹配。(不做sort就更糟了,因为标签的顺序是任意的)。
理想情况下,Haskell (或无序容器?)将提供一种对HashSet的元素进行模式匹配的方法。但是另一种方法可以是通过HashSet.fromList映射Tags ts模式的ts参数,然后比较结果集:
pattern Tags ts <- ((\(Label ts') -> ts' == HashSet.fromList ts) -> True)然而,这是不可能的,因为视图模式函数不能使用模式同义词的参数。但是尝试在view函数之外进行转换:
pattern Tags ts <- ((\(Label ts') -> ts') -> HashSet.fromList ts == ts')这也是不可能的,因为->后面的部分是一个模式,不允许应用函数。
有没有其他方式定义允许这种匹配的模式同义词?
发布于 2017-09-21 21:43:00
Tags真的需要成为一种模式吗?简单地提供一个函数有什么错:
toLabel :: [Tags] -> Label并让用户使用卫士:
someFunction lab | lab == toLabel [TagFoo, TagBar "bar"] = ...https://stackoverflow.com/questions/46344980
复制相似问题