2017-09-21 1 views
1

J'ai récemment essayé de factoriser un ADT - où le nombre de constructeurs a augmenté combinatorically - en une représentation de jeu rétrocompatible:Mapper sur les arguments PatternSynonyms avant de faire correspondre w/ViewPatterns?

data Tag = TagFoo | TagBar !Text | TagBaz !Int ... -- many more 
      deriving (Eq, Generic, Ord, Show) 

newtype Label = Label (HashSet Tag) 
       deriving (Eq, Generic, Show) 

A cette fin, je définissais plusieurs synonymes de motif à l'effet de :

{-# 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] 

avec motif Tags défini comme:

pattern Tags :: [Tag] -> Label 
pattern Tags ts <- ((\(Label ts') -> sort $ HashSet.toList ts') -> ts) 

Malheureusement, formulaire est sujet à erreur, car il faut que les utilisateurs fournissent la liste [Tag] dans le bon Ord er. Sinon, un modèle tel que Tags [TagBar "x", TagFoo] ne correspondra pas Label $ HashSet.fromList [TagBar "x", TagFoo]. (Ne pas faire le sort est encore pire, car alors l'ordre des balises serait arbitraire).

Idéalement, Haskell (ou conteneurs non ordonnés?) Fournirait un moyen de faire correspondre les éléments d'un HashSet s. Mais une autre façon pourrait être de cartographier l'argument ts de Tags ts modèle par HashSet.fromList puis comparer les ensembles résultants:

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

Ceci est impossible, cependant, parce que les arguments d'un synonyme de modèle ne peuvent pas être utilisés par une vue fonction de modèle. Mais essayer de faire la transformation en dehors de la fonction de vue:

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

est également impossible, car la partie après -> est un modèle et ne permet pas l'application de la fonction.

Existe-t-il un autre moyen de définir le synonyme de modèle qui permettrait ce type d'appariement?

+0

'-containers' non ordonnée ne peut pas définir un synonyme non plus! – dfeuer

Répondre

1

Est-ce que Tags doit vraiment être un motif? Quel est le problème de fournir simplement une fonction:

toLabel :: [Tags] -> Label 

et ont les utilisateurs utilisent des gardes:

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