I recently finished reading Learn you a Haskell for great good!. Even though some topics are a bit over my head (Monads anyone?), I wanted to try my hand at a fairly difficult problem. I chose to write a eval function that correctly handles parenthesis and the order of operations. I think this is pretty good, but I can see some things that need improvement.module Eval wheredata Token = Times | Div | Add | Sub | LPren | RPren | Number Float                deriving (Show, Eq)tokenise :: String -> Tokentokenise n = case n of               * -> Times               / -> Div               + -> Add               - -> Sub               ( -> LPren               ) -> RPren               _   -> Number $ read nparse :: String -> [Token]parse s = map tokenise $ tokens sreduce :: [Token] -> Floatreduce tokens = let groups = prenGroups tokens                    results = map reduce groups                    leftover = substitute tokens results                    orderOfOps = [Times, Div, Add, Sub]                in unpackNum $ head $ foldl (flip reduceAllOfOp) leftover orderOfOps-- The expression passed to this function must be ONLY numbers an ops in proper form,-- num, (op, num)*reduceAllOfOp :: Token -> [Token] -> [Token]reduceAllOfOp tok (x:op:y:rest) = if op == tok                                    then let xn = unpackNum x                                             yn = unpackNum y                                             oper = getOp op                                         in reduceAllOfOp tok ((Number $ oper xn yn):rest)                                    else x:op:(reduceAllOfOp tok (y:rest))reduceAllOfOp _ toks = toks-- substitute numbers in for prenthisis groups, pram 1 is the problem, pram 2 is a list of numberssubstitute :: [Token] -> [Float] -> [Token]substitute ts [] = tssubstitute ts ns = let head' = takeWhile (/=LPren) ts                       tail' = tail $ dropWhile (/=LPren) ts                       rprenIdx = findMatchingRPren tail'                       (_, tail'') = splitAt rprenIdx tail'                   in head' ++ [Number $ head ns] ++ substitute tail'' (tail ns)unpackNum :: Token -> FloatunpackNum (Number num) = numunpackNum _            = error Not a number!!isNum :: Token -> BoolisNum (Number _) = TrueisNum _          = FalsegetOp :: Token -> Float -> Float -> FloatgetOp tok = case tok of                Times -> (*)                Div   -> (/)                Add   -> (+)                Sub   -> (-)                _     -> error Not an op!!-- this is also a very big mess, but not quite as bad as `findMatchingRPren`prenGroups :: [Token] -> [[Token]]prenGroups [] = []prenGroups tokens = if all (`elem` tokens) [LPren, RPren]                             -- remove the head of the tokens, returns ... (`...) ...`                    then let tail' = tail $ dropWhile (/=LPren) tokens                             prenLoc = findMatchingRPren tail'                             --      returns ... (`...``) ...`                             (group, rest) = splitAt (prenLoc-1) tail'                             -- the `tail` call is to remove the pren from the list                         in group:prenGroups (tail rest)                    else []-- THIS IS A HORRIBLE FLAMING PIECE OF UGLY JUNK THAT SHOULD BE DESTROYED ON SIGHT!-- unfortunatly it is the only thing that I can think of that works...type Counter = (Int, Int, Bool)findMatchingRPren :: [Token] -> IntfindMatchingRPren t =     let fun = (\(runningCount, splitIdx, done) tok ->               let count = runningCount + case tok of                               RPren -> -1                               LPren -> 1                               _ -> 0              in if done                   then (runningCount, splitIdx, done)                   else (if count == 0                            then (count, splitIdx+1, True)                            else (count, splitIdx+1, False))) :: Counter -> Token -> Counter        res = foldl fun ((1, 0, False) :: Counter) t    in  case res of          (_, idx, _) -> idx-- ================ end of interesting code ===================== --tokens :: String -> [String]tokens [] = []tokens s = let s' = trim s               isOp = (`elem` +-*/())               (head', tail') = if isOp $ head s'                                    then ([head s'], tail s')                                    else break isOp s'           in trim head':tokens tail'-- remove leading and trailing spacetrim :: String -> Stringtrim (' ':ta) = trim tatrim s        = if last s == ' '                    then trim $ init s                    else seval :: String -> Maybe Floateval e = Just $ reduce $ parse eshow' :: [Token] -> Stringshow' = concatMap (\x -> case x of                        Times -> *                        Div   -> /                        Add   -> +                        Sub   -> -                        LPren -> (                        RPren -> )                        Number x -> show x)So my questions are:How can I write the findMatchingRPren function more elegantly?How does my naming look (e.g. the use of head' and tail')?What would be the best way to extract the shared code from substitute and prenGroups?What general improvements can be made to my algorithm?Just anything else you can see that could be improved...
Math eval function for Haskell
haskell;math expression eval