2017-06-04 1 views
0

Donc, je crée un type de donnéesMotif assorti pour les instances alternatives de l'équation

data Expr a = Const a 
    | Expr a :*: Expr a 

Et je définir une instance pour Eq pour ce type de données

instance (Eq m) => Eq (Expr m) where 
    Const a == Const b = a == b 
    (a :*: b) == (c :*: d) = ((a == c) && (b == d)) || ((a == d) && (b == c)) 

Cette définition signifie que l'ordre n'a pas d'importance en comparant deux expressions. Cependant, lorsque j'utilise la correspondance de modèles pour écrire une fonction qui prend Expr s Je ne peux pas écrire

f (Const 1 :*: a) = ... 

, mais il faut aussi écrire

f (a :*: Const 1) = ... 

pour attraper tous les cas, même si si j'où comparer les deux en utilisant (==) il reviendrait vrai.

Existe-t-il un moyen d'écrire juste l'une des expressions ci-dessus et de laisser l'instance de Eq s'occuper du reste? Est-ce que la correspondance de modèle utilise ou requiert une instance de Eq?

Répondre

3

Une instance Eq n'a aucune incidence sur les correspondances de modèle. == est juste une fonction de bibliothèque et vérifie une propriété particulière qui n'a pas forcément grand-chose à voir avec la structure d'implémentation, tandis que les correspondances de modèle ont pour but de déconstruire un type dans sa structure ADT réelle. Cela dit, il est possible de simuler quelque chose de similaire à ce que vous avez demandé, mais je ne pense pas que ce soit une très bonne idée de le faire - cela ne change pas d'échelle et pourrait conduire à d'étranges problèmes plus tard.

{-# LANGUAGE PatternSynonyms, ViewPatterns #-} 

matchConstFactor :: Expr a -> Maybe (a, Expr a) 
matchConstFactor (Const a :*: b) = Just (a, b) 
matchConstFactor (a :*: Const b) = Just (b, a) 
matchConstFact _ = Nothing 

pattern (:.*:) :: a -> Expr a -> Expr a 
pattern a :.*: b <- (matchConstFactor -> Just (a, b)) 
where a :.*: b = Const a :*: b 
3

Est-il possible d'écrire juste un de ce qui précède aux expressions et laisser l'instance (Eq) prendre en charge le reste?

No.

-t-ltrage même utiliser ou nécessitent une instance (Eq)

Seulement en assortissant contre (nombre, caractère ou chaîne) littérales. Vous pouvez voir les règles dans 3.17.2 de https://www.haskell.org/onlinereport/exps.html#pattern-matching et notez que le cas 7 est le seul qui mentionne ==.

Mais vous pouvez utiliser les modèles de vue:

const1 (Const 1 :*: a) = Just a 
const1 (a :*: Const 1) = Just a 
const1 _ = Nothing 

f (const1 -> Just a) = ... 

Cela peut être trop laid si vous avez besoin d'autres symétries dans d'autres cas, et je ne peux pas penser à une solution pour ce au moment.