fork(1) download
  1. import Data.Char
  2. import Data.Maybe
  3. import Control.Monad
  4. import Control.Arrow
  5.  
  6. newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
  7.  
  8. instance (Monad m) => Monad (StateT s m) where
  9. return a = StateT $ \s -> return (a, s)
  10. m >>= k = StateT $ \s -> do
  11. ~(a, s') <- runStateT m s
  12. runStateT (k a) s'
  13.  
  14. instance (MonadPlus m) => MonadPlus (StateT s m) where
  15. mzero = StateT $ \_ -> mzero
  16. m `mplus` n = StateT $ \s -> runStateT m s `mplus` runStateT n s
  17.  
  18. evalStateT m s = do
  19. ~(a, _) <- runStateT m s
  20. --------------------------------------------------------------------------------------------------------------------
  21. type Order = (Int, Bool)
  22. type D = Double
  23. type DD = D -> D
  24. type DDD = D -> D -> D
  25.  
  26. data Oper = Prinfix (DD, Order) | Prefix DD | Postfix DD | Infix (DDD, Order)
  27. data Expr = Operand D | Operator Oper | Statement [Expr]
  28.  
  29. (leftass, rightass) = (True, False)
  30. makeGuard d g = Operator $ d (g, (1, True))
  31.  
  32. toOp' d xs l = lookup l xs >>= Just . Operator . d
  33.  
  34. toOp 0 = toOp' Prinfix [("-", (negate, (5, leftass)))]
  35. toOp 1 = toOp' Prefix [("sqr", (^2))]
  36. toOp 3 = toOp' Postfix [("!", \x -> product [1..x])]
  37. toOp 4 = toOp' Infix [("+", ((+), (5, leftass))), ("-", ((-), (5, leftass))),
  38. ("*", ((*), (6, leftass))), ("/", ((/), (6, leftass))), ("^", ((**), (7, rightass)))]
  39.  
  40. modifyVal g s = s >>= return . g
  41.  
  42. parse = modifyVal (Statement . (makeGuard Prinfix id :)) $ parse' 0 where
  43. add i t = modifyVal (t :) $ parse' i
  44. parse' i = StateT (listToMaybe . lex) >>= parse'' i
  45. parse'' pos l
  46. | l == "" || l == ")" = guard (pos >= 3) >> return [makeGuard Infix undefined]
  47. | isDigit $ head l = guard (pos <= 2) >> add 3 (Operand $ read l)
  48. | l == "(" = guard (pos <= 2) >> parse >>= add 3
  49. | pos <= 1 = choose 1
  50. | pos <= 4 = choose 4
  51. where choose i = uncurry add =<< case (toOp i l, guard (pos < i) >> toOp (i - 1) l) of
  52. (Just t, Nothing) -> return (i `rem` 2 + 1, t)
  53. (Nothing, Just t) -> return (i, t)
  54. _ -> mzero
  55.  
  56. eval (Operand t) = t
  57. eval (Statement t) = fst . snd $ eval' (0, True) (undefined, t) where
  58. cond (pr1, as1) (pr2, as2) = pr1 > pr2 || pr1 == pr2 && if as1 == as2 then as1
  59. else error "cannot mix two operators"
  60. eval' op (n, ots@(Operator o : ts)) = case o of
  61. Prefix g -> h g $ uncurry eval'
  62. Postfix g -> eval' op (g n, ts)
  63. Prinfix (g, opt) -> h g $ until (cond opt . fst) (eval' opt . snd)
  64. Infix (g, opt) -> (,) opt . (,) n $ if cond op opt then ots else Operator (Prinfix (g n, opt)) : ts
  65. where h g f = second (first g) $ f ((10, undefined), (undefined, ts))
  66. eval' op (n, t : ts) = eval' op (eval t, ts)
  67.  
  68. calc = fmap eval . evalStateT parse
  69.  
  70. main = mapM_ (print . calc)
  71. [ "2 + 3"
  72. , "4 - 3"
  73. , "2 + (-3)"
  74. , "4 * 5"
  75. , "6/4"
  76. , "1.2 + 1/2"
  77. , "1/(-3)"
  78. , "0.5 + 0.2"
  79. , "3 ^ 2 ^ 2"
  80. , "17654/342"
  81. , "2/3 ^ 2"
  82. , "(2/3) ^ 2"
  83. , "(2 + 3) / (2 - 2)"
  84. , "2 + 345 + + + + 6"
  85. , " - sqr 5! +(-sqr(1 - 2^ 3) ^sqr 2 *9 !) "
  86. , "5 + 9 3"
  87. , "sqr sqr 3"
  88. ]
Success #stdin #stdout 0s 6352KB
stdin
Standard input is empty
stdout
Just 5.0
Just 1.0
Just (-1.0)
Just 20.0
Just 1.5
Just 1.7
Just (-0.3333333333333333)
Just 0.7
Just 81.0
Just 51.619883040935676
Just 0.2222222222222222
Just 0.4444444444444444
Just Infinity
Nothing
Just (-2.09193100128e12)
Nothing
Nothing