【问题标题】:Map over PatternSynonyms args before matching w/ ViewPatterns?在匹配 w/ViewPatterns 之前映射 PatternSynonyms 参数?
【发布时间】:2017-09-21 21:43:00
【问题描述】:

我最近尝试将 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(或无序容器?)将提供一种模式匹配HashSets 元素的方法。但另一种方法可能是将Tags ts 模式的ts 参数映射到HashSet.fromList,然后比较结果集:

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

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

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

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

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

【问题讨论】:

  • unordered-containers 也无法定义这样的同义词!

标签: haskell pattern-matching


【解决方案1】:

Tags 真的需要成为一个模式吗?简单地提供一个函数有什么问题:

toLabel :: [Tags] -> Label

并让用户使用警卫:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多