Haskell Frage: Zwangsdatentypen anzeigen verwenden
-
13-09-2019 - |
Frage
Code:
data Exp a = Const a | Eq (Exp a) (Exp a)
Ich möchte, dass die Const a einen Wert vom Typ Show enthalten, so dass ich es später drucken können. Also in C # würde ich schreiben:
class Const : Exp { IShow X; }
class Eq : Exp { Exp X, Y; }
Wie kann ich das tun in Haskell?
Lösung
{-# LANGUAGE GADTs #-}
data Exp a where
Const :: Show a => a -> Exp a
Eq :: Exp a -> Exp a -> Exp a
Wenn Sie für verschiedene Datentypen in verschiedenen Zweigen des Eq
zulassen will, dass auch in Ordnung ist.
data Exp where
Const :: Show a => a -> Exp
Eq :: Exp -> Exp -> Exp
Andere Tipps
Sie können dies tun, indem er sagte
data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
Aber das ist fast immer eine schlechte Idee, weil es jede Funktion, die Exp
verwendet zwingt die Show-Einschränkung zu erwähnen, auch wenn es nie die Show
Methoden verwendet. Stattdessen setzen die Show-Einschränkung auf nur die Funktionen für sie relevant ist. Siehe Real World Haskell für eine Erklärung.
Wenn alles, was Sie über das Argument wissen wollen, ist zu Const
, dass Sie es show
können, warum speichert nicht nur den resultierenden String
Wert im Konstruktor statt? Zum Beispiel:
data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
Dies ähnelt C # Version.
die zweite Frage zu beantworten, in den Kommentaren gefragt ist Eq (Const 0) (Const "")
nicht erreichbar mit dem Datentyp Sie haben, weil Exp Integer
und Exp String
ist nicht vom gleichen Typ. Eine Möglichkeit ist, etwas zu tun, wie
data Exp = forall a . Show a => Const a | Eq Exp Exp
Ob das Sie tun etwas Gutes hängt davon ab, was Sie vorhaben, mit der Art auf zu tun.
Edit: Das tut Spracherweiterungen erfordern aktiviert sein, wie erwähnt
.Ich möchte nur erklären, um Ihren Datentyp eine Instanz der Typklasse 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 ++ " ]"
Sehen Sie, was passiert, wenn man diese in GHCI laden und zu tun:
*Main> let x = Eq (Const 1) (Eq (Const 2) (Const 3))
*Main> x
[1 , [2 , 3] ]
Die Beantwortung Kommentar:
Sie können ganz einfach mit verschiedenen Arten umgehen. Angenommen, Sie mathematische Ausdrücke analysieren möchten. Sie können die folgende Struktur haben, zum Beispiel:
data Expr = Var String | Sum (Expr) (Expr) | Number Int | Prod (Expr) (Expr)
Das ist genug, um jeden Ausdruck von Summen und Produkten von Zahlen und benannten Variablen gemacht darzustellen. Zum Beispiel:
x = Sum (Var "x") (Prod (Number 5) (Var "y"))
steht: x + 5j
Um dies zu drucken schön ich tun würde:
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
Dies würde den Trick tun. Sie könnten auch GADTs verwenden:
data Expr where
Var :: String -> Expr
Sum :: Expr -> Expr -> Expr
etc ... und dann instanziiert dies als Show.