1
votes

I'm new to haskell and have started it because I'm doing it at UNI, I've had previous experience in C, C# and HTML, CSS. We had a lab this week where we were given the code :

data Token = Plus | Minus | Times | Divided_By | Power | Num {number :: Double}
deriving (Show, Eq)

type Expression = [Token]

tokenizer :: String -> Expression
tokenizer expression_as_string = case expression_as_string of
   ""    -> []
   c: cs -> case c of
      '+' -> Plus        : tokenizer cs
      '-' -> Minus       : tokenizer cs
      '*' -> Times       : tokenizer cs
      '/' -> Divided_By  : tokenizer cs
      '^' -> Power       : tokenizer cs
      _ | c `elem` ['0' .. '9'] -> case reads expression_as_string of
                                      [(value, rest)] -> Num value : tokenizer rest
                                      _               -> error "Could not read number"
        | c `elem` [' ', '\t'] -> tokenizer cs
        | otherwise -> error "Unknown Symbol"

expression_to_string :: Expression -> String
expression_to_string expr = case expr of
   []    -> ""
   e: es -> case e of
      Plus       -> " + "     ++ expression_to_string es
      Minus      -> " - "     ++ expression_to_string es
      Times      -> " * "     ++ expression_to_string es
      Divided_By -> " / "     ++ expression_to_string es
      Power      -> " ^ "     ++ expression_to_string es
      Num x      -> (show x)  ++ expression_to_string es

eval_string_expression :: String -> String
eval_string_expression s = expression_to_string (eval (tokenizer s))

So now we are meant to implement out own function called eval which should solve this equation, when typed in ghci:

eval [Num 3.2, Plus, Minus, Num 4.2, Minus, Num 5.3, Plus, Num 6.3] [Num {number = 0.0}]

So at this point i've used pattern matching (judging that i understand it) and got this far:

eval :: Expression -> Expression
eval list = case list of
   [] -> []
   [Num x, op, Num y] -> case op of
      Plus           -> [Num (x + y)]
      Minus         -> [Num (x - y)]
      Times         -> [Num (x * y)]
      Divided_By -> [Num (x / y)]
      Power         -> [Num (x ** y)]
      _                -> error "......"

Now if i type this into ghci: eval[Num 3.1, Plus, Num 4.2] it returns 7.300000000001 because it is a double, now im not sure if this is correct. Though i do know that this is non-exhaustive because i havent taken care of all the possibilities. What i need help with is taking a negative number into consideration such as Minus, Plus which should return a Minus but I also need to take note of how order works, such as Powers, then Multiplication/Division then Addition/Subtraction. Our lecturer has given us the return value if the eval function is called: eval ((eval [Num x, op, Num y]) ++ op_next: remaining_expr)

So if anyone can help, if you understand what i am saying it would be helpful, ohh and go easy please im still trying to learn! :) This lab is meant to teach us pattern matching but i still don't fully understand it.

I probably should note that I know what I am meant to do but just not how to write it correctly!

1
Consider matching it as (Num x : op : Num y : op_next : remaining_expr) instead. You can make that change and it won't affect how your function currently works. Then start thinking about what you can do with op_next and remaining_expr. If you need to worry about order of operations then think about what kind of pattern match you could do to find those cases. What are the different interactions between the different operators? Make sure that [Num 1, Plus, Num 2, Times, Num 3] is treated as 1 + (2 * 3). Get that one working, then implement the next rule. See if you can find a pattern.bheklilr
I'm voting to close this question as off-topic because it is specialized to a specific homework assignment and unclear.sclv

1 Answers

-2
votes

Oh hi coursemate, yeah this week's lab drives me crazy too..

I did this in 9 cases (which I think it's terrible and I need to find a better way, it works fine though).

What I did is to set up the patterns which cover all possible inputs

  1. px : Num x : op : py : Num y : opn : r
  2. px : Num x : op : Num y : opn : r
  3. Num x : op : py : Num y : opn : r
  4. Num x : op : Num y : opn : r
  5. Num x : op : Num y : []
  6. Num x : op : py : Num y : []
  7. px : Num x : op : Num y : []
  8. px : Num x : op : py : Num y : []
  9. _

where px and py are the number prefix (Plus / Minus)

In cases 2 ~ 3, they'll call eval again which process to case 1, same as cases 5 ~ 7, they'll process to case 8. So case 1 & 8 are cases which doing the actual calculations.

Case 1 is where you deal with the binding_power function (which calculates the operator priority);

Case 8 is where you do the final calculation (beware of zero-division), you may set-up a where clause like to translate a negative number:

tx = (if px == Minus then -1 else 1) * x
ty = (if py == Minus then -1 else 1) * y

If you want spoilers, here's the link: http://pastebin.com/Vq8PC6Z3