Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Custom Datatype to String

Tags:

haskell

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 am supposed to do is later create an expression based on the datatype. For example

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

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

The problem I am facing is to create another type or data type to recognize if it is an addition or multiplication symbol it is supposed to print out. What I would like to do is something like this in pseudo code

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

How am I supposed to do this?

like image 583
Salviati Avatar asked Oct 09 '17 16:10

Salviati


People also ask

How do you change a type into a string?

There are two ways for changing any data type into a String in Python : Using the str() function. Using the __str__() function.

How do you convert a datatype to a string in Python?

To convert an integer to string in Python, use the str() function. This function takes any data type and converts it into a string, including integers. Use the syntax print(str(INT)) to return the int as a str , or string.


2 Answers

You can not write references to types as constructor name. 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 considers the fact that there is a type with the same name, just a coincidence. You have to add the type of operator/function as first argument. So:

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

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

Now you thus have to replace your:

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

with:

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

Based on that, we can define some helper 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 something, it only generates a string, you can do whatever you want with that string).

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

For example:

*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))"
like image 165
Willem Van Onsem Avatar answered Oct 16 '22 22:10

Willem Van Onsem


When you pattern match, you need to match on the constructor you passed in. In your example, an Expr can have an Operator constructor that contains the relevant information to print:

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

Now you just 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 aren't printing anything to the screen with these "print" functions. Instead, you are converting them from your datatype to a string. There is a common typeclass that does that called Show. You could also just create instances of show for your types, and use that function to display them instead:

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

and then use show instead:

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

When you have a simple instance of show, you can also just have it derived automatically for you using the same syntax as you are using for deriving Eq:

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

To deal with creating an instance of Expr, again you use the various constructors to do so:

let anExpr = Operator Add (Num 3.0) (Num 4.0)
like image 30
jkeuhlen Avatar answered Oct 16 '22 21:10

jkeuhlen