在匹配w / ViewPatterns之前映射PatternSynonyms args?

时间:2017-09-21 13:16:37

标签: haskell pattern-matching

我最近试图将一个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)

不幸的是,这种形式容易出错,因为它要求用户在正确的[Tag]中提供Ord列表。否则,Tags [TagBar "x", TagFoo]之类的模式将与Label $ HashSet.fromList [TagBar "x", TagFoo]不匹配。 (不是sort更糟糕的是,因为那时标签的顺序是任意的。)

理想情况下,Haskell(或无序容器?)将提供一种模式匹配HashSet s元素的方法。但另一种方法是将ts模式的Tags ts参数映射到HashSet.fromList,然后比较结果集:

pattern Tags ts <- ((\(Label ts') -> ts' == HashSet.fromList ts) -> True)

然而,这是不可能的,因为视图模式函数不能使用模式同义词的参数。但是试图在视图函数之外进行转换:

pattern Tags ts <- ((\(Label ts') -> ts') -> HashSet.fromList ts == ts')

也是不可能的,因为->之后的部分是一个模式,不允许函数应用。

是否有其他方法可以定义允许这种匹配的模式同义词?

1 个答案:

答案 0 :(得分:1)

Tags真的需要成为一种模式吗?简单地提供功能有什么问题:

toLabel :: [Tags] -> Label

让用户使用警卫:

someFunction lab | lab == toLabel [TagFoo, TagBar "bar"] = ...