2017-09-21 47 views
1

我最近試圖重構一個ADT - ,其中構造的數量已經增長combinatorically - 成向後兼容的組表示:匹配w/ViewPatterns之前通過PatternSynonyms args映射?

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) 

不幸的是,這表格很容易出錯,因爲它要求用戶在正確的Ord er中提供[Tag]列表。否則,像Tags [TagBar "x", TagFoo]這樣的模式將不匹配Label $ HashSet.fromList [TagBar "x", TagFoo]。 (不過,sort甚至更​​糟糕,因爲標籤的順序將是任意的)。

理想情況下,Haskell(或無序容器?)將提供模式匹配HashSet的元素的方法。但另一種方式可能是通過HashSet.fromListTags ts模式的ts參數映射,然後比較兩者的集合:

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

這是不可能的,但是,因爲一個圖案代名詞的論據不能由視圖模式功能可以使用。但是,試圖做視圖功能之外的改造:

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

也是不可能的,因爲->之後的部分是一個模式,不允許的功能應用。

是否有一些其他方式來定義允許這種匹配的模式同義詞?

+0

'無序-containers'也不能定義這樣的代名詞! – dfeuer

回答

1

Tags確實需要一個模式?出了什麼問題只是提供了一個功能:

toLabel :: [Tags] -> Label 

,並有用戶使用衛士:

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