The main function...

val :: String -> Int

val s = valx 0 s

This works by calling its auxiliary function...

valx n [] = n

valx n (c:cs) =

case c of

'+' -> n + valx 0 cs

'-' -> n - valx 0 cs

_ -> valx ((n * 10) + (ord c - ord '0')) cs

And so...

*Main Data.Char> val "1+2+34-5+67-8+9"

-18

Wrong answer.

The reason is that doing it recursively implicitlty brackets from the end of the string, so we are working out 1+(2+(34-(5+(67-(8+9))))) but really we want to work out (((((1+2)+34)-5)+67)-8)+9

OK so I want an auxiliary function that takes an accumulator for the whole expression, and as I go along a smaller accumulator for the value of the number I'm working through. And a number -1 or +1 for the last sign character I encountered.

At the start, the accumulators are zero and the sign is +1.

Each time I hit either a + or a - character I either add or subtract the value of my current number to or from the accumulator. Also I set the sign for the next number, and set the little accumulator back to

zero.

When I hit a digit I use it to increase the value of the current number.

So I get this:

eval :: String -> Int

eval s = evalx 0 0 1 s

evalx :: Int -> Int -> Int -> String -> Int

evalx acc cur sgn "" =

acc + (sgn * cur)

evalx acc cur sgn (c:cs) =

case c of

'+' -> evalx (acc + (sgn * cur)) 0 1 cs

'-' -> evalx (acc + (sgn * cur)) 0 (-1) cs

_ -> evalx acc ((cur * 10) + (ord(c) - ord('0'))) sgn cs

*Main Data.Char> eval "1+2+34-5+67-8+9"

100

This one does work.

## No comments:

## Post a Comment