pergunta Haskell: restringir os tipos de dados de usar programa
-
13-09-2019 - |
Pergunta
Código:
data Exp a = Const a | Eq (Exp a) (Exp a)
Eu quero o Const um para conter um valor do tipo programa para que eu possa imprimi-lo mais tarde. Assim, em C # eu iria escrever:
class Const : Exp { IShow X; }
class Eq : Exp { Exp X, Y; }
Como posso fazer isso em Haskell?
Solução
{-# LANGUAGE GADTs #-}
data Exp a where
Const :: Show a => a -> Exp a
Eq :: Exp a -> Exp a -> Exp a
Se você deseja permitir para diferentes tipos de dados em diferentes ramos da Eq
tudo bem também.
data Exp where
Const :: Show a => a -> Exp
Eq :: Exp -> Exp -> Exp
Outras dicas
Você pode fazer isso, dizendo
data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
Mas isso é quase sempre uma má idéia, porque obriga cada função que usa Exp
mencionar o show restrição, mesmo que nunca usa os métodos Show
. Em vez disso, colocar o show restrição em apenas as funções que ele é relevante para. Consulte Real World Haskell para obter uma explicação.
Se tudo que você quer saber sobre o argumento para Const
é que você pode show
-lo, porque não basta armazenar o valor String
resultando no construtor em vez disso? Por exemplo:
data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
Esta se assemelha a sua versão C #.
Para responder à segunda questão, perguntou nos comentários, Eq (Const 0) (Const "")
não é possível com o tipo de dados que você tem, porque Exp Integer
e Exp String
não são do mesmo tipo. Uma opção é fazer algo parecido
data Exp = forall a . Show a => Const a | Eq Exp Exp
Se isso vai fazer qualquer bom depende do que você está pensando em fazer com o tipo.
Edit:. Isto requer extensões de linguagem a ser habilitado como mencionado
Gostaria apenas de declarar o tipo de dados de uma instância da classe tipo 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 ++ " ]"
Veja o que acontece quando você carrega isso em ghci e fazer:
*Main> let x = Eq (Const 1) (Eq (Const 2) (Const 3))
*Main> x
[1 , [2 , 3] ]
Respondendo comentário:
Você pode facilmente lidar com diferentes tipos. Suponha que você queira analisar as expressões matemáticas. Você pode ter a seguinte estrutura, por exemplo:
data Expr = Var String | Sum (Expr) (Expr) | Number Int | Prod (Expr) (Expr)
Este é o suficiente para representar qualquer expressão feita de somas e produtos de números e variáveis ??nomeadas. Por exemplo:
x = Sum (Var "x") (Prod (Number 5) (Var "y"))
representa: x + 5y
Para imprimir este lindamente eu faria:
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
Esta faria o truque. Você também pode usar GADTs:
data Expr where
Var :: String -> Expr
Sum :: Expr -> Expr -> Expr
etc ... e depois instanciar isso como Show.