Convert user data type to string

If I have three data types named Expr , Op and Fu , like this.

 data Expr = Num Double | X | Operator Op Expr Expr | Function Fu Expr deriving (Eq) data Op = Add | Mul deriving (Eq) data Fu = Sin | Cos deriving (Eq) 

What I have to do is create an expression based on a data type. for instance

 let anExpr = Add (Num 3.0) (Num 4.0) 

And how to print the corresponding expression, in this case it should just be "3.0 + 4.0".

The problem I am facing is creating another type or data type to recognize if it is the addition or multiplication symbol that it should print. I would like to do something like this in pseudo code

 printOut (Num n) = show n printOut X = "x" printOut (Op ab) = printOut a ++ 'printOutRightOp' ++ printOut b printOut (Fu a) = 'printOutRightFu' ++ printOut a 

How am I supposed to do this?

+5
source share
2 answers

You cannot write type references as the name of a constructor . In your code:

 data Expr = Num Double | X | Op Expr Expr | Fu Expr deriving (Eq) 

Op and Fu are the names of the constructors . Haskell believes that there is a type with the same name, just a coincidence. You must add an operator / function type as the first argument . So:

 data Expr = Num Double | X | Op Op Expr Expr | Fu Fu Expr deriving (Eq) 

Now the second Op and Fu set the types of the first parameters.

Now you should replace yours:

 let anExpr = Add (Num 3.0) (Num 4.0) 

with:

 let anExpr = Op Add (Num 3.0) (Num 4.0) 

Based on this, we can define some auxiliary functions:

 showOp :: Op -> String showOp Add = "+" showOp Mul = "*" showFu :: Fu -> String showFu Sin = "sin" showFu Cos = "cos" 

Now we can use these helper functions when we define our showExpr (I would not call it printOut , since the function does not print anything, it only generates a string, you can do whatever you want with this string).

 showExpr :: Expr -> String showExpr (Num n) = show n showExpr X = "x" showExpr (Op oab) = '(' : showExpr a ++ ')' : showOp o ++ '(' : showExpr b ++ ")" showExpr (Fu fa) = showFu f ++ '(' : showExpr a ++ ")" 

For instance:

 *Main> showExpr (Op Add (Num 3.0) (Num 4.0)) "(3.0)+(4.0)" *Main> showExpr (Op Add (Num 3.0) (Fu Sin (Num 4.0))) "(3.0)+(sin(4.0))" 
+5
source

When matching a template, you need to match the constructor in which you passed. In your example, Expr may have an Operator constructor that contains relevant print information:

 printOut (Num n) = show n printOut X = "x" printOut (Operator op ab) = printOut a ++ printOp op ++ printOut b printOut (Function fu a) = printFun fu ++ printOut a 

Now you simply define additional pattern matches for your operators and functions:

 printOp Add = "+" printOp Mul = "x" printFun Sin = "Sin" printFun Cos = "Cos" 

In addition to what @WillemVanOnsem wrote, you actually don't print anything on the screen with these print features. Instead, you convert them from your data type to a string. There is a regular type called Show . You can also simply create show instances for your types and use this function to display them:

 instance Show Fu where show Sin = "Sin" show Cos = "Cos" 

and then use Show instead:

 printOut (Function fu a) = show fu ++ printOut a 

If you have a simple instance of Show , you can also just get it automatically for you, using the same syntax that you use to get Eq :

 data Fu = Sin | Cos deriving (Show, Eq) 

To handle creating an Expr instance, you again use various constructors:

 let anExpr = Operator Add (Num 3.0) (Num 4.0) 
+3
source

Source: https://habr.com/ru/post/1272458/


All Articles