Haskell pregunta: limitar los tipos de datos a utilizar Mostrar
-
13-09-2019 - |
Pregunta
Código:
data Exp a = Const a | Eq (Exp a) (Exp a)
Quiero que el Const a para contener un valor de tipo de presentación para que pueda imprimir más tarde. Así que en C # que iba a escribir:
class Const : Exp { IShow X; }
class Eq : Exp { Exp X, Y; }
¿Cómo puedo hacer que en Haskell?
Solución
{-# LANGUAGE GADTs #-}
data Exp a where
Const :: Show a => a -> Exp a
Eq :: Exp a -> Exp a -> Exp a
Si desea permitir la variación de los tipos de datos en diferentes ramas de Eq
eso también está bien.
data Exp where
Const :: Show a => a -> Exp
Eq :: Exp -> Exp -> Exp
Otros consejos
Usted puede hacer esto diciendo
data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
Pero esto es casi siempre una mala idea ya que obliga a todas las funciones que utiliza Exp
mencionar el programa de restricción, aunque nunca utiliza los métodos Show
. En su lugar, poner el programa de restricción en tan sólo las funciones que es relevante para. Ver Real World Haskell una explicación.
Si todo lo que quiere saber sobre el argumento de Const
es que se puede show
que, ¿por qué no almacenar el valor resultante String
en el constructor en su lugar? Por ejemplo:
data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
Esto se parece mucho a su versión C #.
Para responder a la segunda pregunta, hecha en los comentarios, Eq (Const 0) (Const "")
no es alcanzable con el tipo de datos que tiene, ya Exp Integer
y Exp String
no son del mismo tipo. Una opción es hacer algo como
data Exp = forall a . Show a => Const a | Eq Exp Exp
Ya sea que no le hará ningún bien depende de lo que estés pensando en hacer con el tipo.
Edit: Esto requiere extensiones de lenguaje para ser habilitado como se mencionó
.Me acaba de declarar el tipo de datos de una instancia de la clase Mostrar tipo:
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 ++ " ]"
Mira lo que ocurre cuando se carga en este ghci y hacer:
*Main> let x = Eq (Const 1) (Eq (Const 2) (Const 3))
*Main> x
[1 , [2 , 3] ]
Responder a un comentario:
Puede ocuparse fácilmente de diferentes tipos. Supongamos que se desea analizar expresiones matemáticas. Usted puede tener la siguiente estructura, por ejemplo:
data Expr = Var String | Sum (Expr) (Expr) | Number Int | Prod (Expr) (Expr)
Esto es suficiente para representar cualquier expresión hecha de sumas y productos de números y variables con nombre. Por ejemplo:
x = Sum (Var "x") (Prod (Number 5) (Var "y"))
representa: x + 5y
Para imprimir esta muy bien que lo haría:
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
Esto haría el truco. También es posible usar GADTs:
data Expr where
Var :: String -> Expr
Sum :: Expr -> Expr -> Expr
etc ... y luego una instancia esto como Mostrar.