module Operation
( add
, sub
, mul
, divide
, power
) where

import Stack

modifyStack :: (Double -> Double -> Double) -> Maybe Double -> Maybe Double -> Stack -> Stack
modifyStack _ Nothing _ st = st
modifyStack _ _ Nothing st = st
modifyStack fn (Just a) (Just b) st = flip poppush st $ fn a b

binaryOp :: (Double -> Double -> Double) -> Stack -> Stack
binaryOp op stack = modifyStack op first second stack
  where
    nth :: Int -> Stack -> Maybe Double
    nth n st = if n > length (values st)
                 then Nothing
                 else Just $ values st !! n
    first = nth 1 stack
    second = nth 2 stack

add :: Stack -> Stack
add = binaryOp (+)

sub :: Stack -> Stack
sub = binaryOp (-)

mul :: Stack -> Stack
mul = binaryOp (*)

divide :: Stack -> Stack
divide = binaryOp (/)

power :: Stack -> Stack
power = binaryOp (**)
