question Haskell: contraindre les types de données à utiliser show
-
13-09-2019 - |
Question
Code:
data Exp a = Const a | Eq (Exp a) (Exp a)
Je veux que le Const a pour contenir une valeur de type émission afin que je puisse l'imprimer ultérieurement. Donc, en C # je voudrais écrire:
class Const : Exp { IShow X; }
class Eq : Exp { Exp X, Y; }
Comment puis-je faire dans Haskell?
La solution
{-# LANGUAGE GADTs #-}
data Exp a where
Const :: Show a => a -> Exp a
Eq :: Exp a -> Exp a -> Exp a
Si vous souhaitez autoriser pour différents types de données dans les différentes branches de Eq
qui est très bien aussi.
data Exp where
Const :: Show a => a -> Exp
Eq :: Exp -> Exp -> Exp
Autres conseils
Vous pouvez le faire en disant
data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
Mais ce qui est presque toujours une mauvaise idée, car elle oblige toutes les fonctions qui utilise Exp
mentionner la contrainte de spectacle, même si elle utilise jamais les méthodes de Show
. Au lieu de cela, mettre la contrainte de spectacle uniquement sur les fonctions qu'il est pertinent pour. Voir Real World Haskell pour une explication.
Si tout ce que vous voulez savoir sur l'argument de Const
est que vous pouvez show
, pourquoi ne pas simplement stocker la valeur String
résultant du constructeur à la place? Par exemple:
data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
Cette version ressemble étroitement C #.
Pour répondre à la deuxième question, posée dans les commentaires, Eq (Const 0) (Const "")
n'est pas réalisable avec le type de données que vous avez parce Exp Integer
et Exp String
ne sont pas du même type. Une option est de faire quelque chose comme
data Exp = forall a . Show a => Const a | Eq Exp Exp
Que cela vous faire du bien dépend de ce que vous avez l'intention de faire avec le type.
Edit: Cela nécessite des extensions de langage être activé comme mentionné
.Je voudrais juste déclarer votre datatype une instance de la classe de type Show:
data Exp a = Const a | Eq (Exp a) (Exp a)
instance (Show a) => Show (Exp a) where
show (Const a) = show a
show (Eq x y ) = "[ " ++ show x ++ " , " ++ show y ++ " ]"
Regardez ce qui se passe lorsque vous chargez ceci dans ghci et faites:
*Main> let x = Eq (Const 1) (Eq (Const 2) (Const 3))
*Main> x
[1 , [2 , 3] ]
Répondre à un commentaire:
Vous pouvez facilement faire face à différents types. Supposons que vous voulez analyser des expressions mathématiques. Vous pouvez avoir la structure suivante, par exemple:
data Expr = Var String | Sum (Expr) (Expr) | Number Int | Prod (Expr) (Expr)
Il suffit de représenter toute expression faite des sommes et des produits de nombres et variables nommées. Par exemple:
x = Sum (Var "x") (Prod (Number 5) (Var "y"))
représente: x + 5y
Pour imprimer ce magnifique que je ferais:
instance Show Expr where
show (Var s) = show s
show (Sum x y) = (show x) ++ " + " (show y)
show (Prod x y) = (Show x) ++ (show y)
show (Number x) = show x
Ce serait faire l'affaire. Vous pouvez également utiliser GADTs:
data Expr where
Var :: String -> Expr
Sum :: Expr -> Expr -> Expr
etc ... puis instancier ce qu'Afficher.