module CalcState (CalcState, startState, calcValue, addDigit, op, eval, clear, calcBase, setBase) where -- This is the state of the calculator: the current value, the current -- partial function, and a flag to tell us whether the next digit will -- start a new number (actually, the sense is reversed from that, but you -- get the idea) data CalcState = CS { calcValue :: Int, calcOp :: Int -> Int, startNew :: Bool, calcBase :: Int } startState :: CalcState startState = CS 0 id False 10 -- Add a single digit to the state. Depending on the boolean value, -- this could be the start of a new number, or the new rightmost digit -- of the existing number addDigit :: Int -> CalcState -> CalcState addDigit n (CS r f True base) = CS n f False base addDigit n (CS r f False base) = CS (r * base + n) f False base -- Apply an operation to the calculator. In fact, this partially applies -- the operation to what's already there. The current partial operation -- is applied to the current number. op :: (Int -> Int -> Int) -> CalcState -> CalcState op f (CS r g _ base) = CS (g r) (f (g r)) True base -- Evaluate the state. That is, apply the current partial operation to -- the current number, resetting everything else eval :: CalcState -> CalcState eval (CS r f _ base) = CS (f r) id True base -- Clear the state. clear :: CalcState -> CalcState clear = const startState setBase :: Int -> CalcState -> CalcState setBase newBase cs = cs { calcBase = newBase }