skiboy108
skiboy108

Reputation: 59

Parsing Input Using Expression Tree

So I am trying to take a user input and then parse it into an expression that I have set up an expression tree for. The expression tree that I have is:

data Expression = State [Float] Float 
                    | Const Float
                    | Plus Expression Expression
                    | Times Expression Expression
                    | Minus Expression Expression
                    | Divide Expression Expression
                    | Uminus Expression
                    deriving(Show, Read)

And then I am trying to take the input and then parse it using the following two lines.

expression <- getLine
read expression

Is there something that I am missing regarding either getting the input or in my use of read? The error that it is giving me is:

Main.hs:94:3: error:
    • No instance for (Read (IO a0)) arising from a use of ‘read’
    • In a stmt of a 'do' block: read expression
      In the expression:
        do putStrLn "Input an expression to evaluate"
           expression <- getLine
           read expression
           print ("Hello World")
           ....
      In an equation for ‘main’:
          main
            = do putStrLn "Input an expression to evaluate"
                 expression <- getLine
                 read expression
                 ....

Upvotes: 0

Views: 159

Answers (1)

gltronred
gltronred

Reputation: 256

If you use something inside a do-notation, it is in the Monad (or Applicative, if you turn on some language pragmas).

So, your code

expression <- getLine
read expression

is written inside a monad. Then read expression is expected to have a type m a for some monad m and some type a. Compiler can infer m from the type of getLine :: IO String, so m is IO.

But read has type read :: Read b => String -> b. Therefore, b should be IO a. But there is no instance of Read for IO a, you can't convert a string into an IO action returning something.

The problem is that you want to perform pure computation. To do so you have to use let:

expression <- getLine
let parsed = read expression :: Expression
print parsed

Here I use let to bind a name parsed to the result of read expression. Then you have to do something with a value parsed, for example, you can print it.

I have to specify the type because print can work with anything that has Show instance, and the compiler can't select the specific type of parsed. If I write something more specific, like performOperation :: Expression -> IO (), then the type declaration can be omitted.

Upvotes: 1

Related Questions