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?

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top