evaluate :: Instruction -> AsolEvent ()
evaluate ins =
  case ins of
    Push n -> modify (n :)
    Top n ->
      let top :: Int -> Stack -> Stack
          top i xs =
            let (as,bs) = splitAt i xs
            in head bs : as ++ tail bs
      in stackop n $ modify (top n)
    Add -> stackbinop (+)
    Div -> stackbinop div
    Dup -> stackop 1 $ modify (\(x:xs) -> x : x : xs)
    Emit ->
      stackop 1 $ get >>= \x -> liftIO (putChar $ chr $ fromIntegral $ head x)
    Mod -> stackbinop mod
    Mul -> stackbinop (*)
    Pow -> stackbinop (^)
    Fact ->
      let factorial n = product [1 .. n]
      in stackop 1 $ modify (\(x:xs) -> factorial x : xs)
    Pop -> stackop 1 $ modify tail
    Print -> stackop 1 $ get >>= \x -> liftIO (print $ head x)
    Read -> (evaluate . Push) =<< fmap read (liftIO getLine)
    Sub -> stackbinop (-)
    Swap -> stackop 2 $ modify (\(x:y:xs) -> y : x : xs)
    ShowStack -> get >>= liftIO . print
evaluate :: Instruction -> AsolEvent ()
evaluate ins =
  case ins of
    Push n -> modify (n :)
    Top n ->
      let top :: Int -> Stack -> Stack
          top i xs =
            let (as,bs) = splitAt i xs
            in head bs : as ++ tail bs
      in stackop n $ modify (top n)
    Add -> stackbinop (+)
    Div -> stackbinop div
    Dup -> stackop 1 $ modify (\(x:xs) -> x : x : xs)
    Emit ->
      stackop 1 $ get >>= \x -> liftIO (putChar $ chr $ fromIntegral $ head x)
    Mod -> stackbinop mod
    Mul -> stackbinop (*)
    Pow -> stackbinop (^)
    Fact ->
      let factorial n = product [1 .. n]
      in stackop 1 $ modify (\(x:xs) -> factorial x : xs)
    Pop -> stackop 1 $ modify tail
    Print -> stackop 1 $ get >>= \x -> liftIO (print $ head x)
    Read -> (evaluate . Push) =<< fmap read (liftIO getLine)
    Sub -> stackbinop (-)
    Swap -> stackop 2 $ modify (\(x:y:xs) -> y : x : xs)
    ShowStack -> get >>= liftIO . print
evaluate ins =
  case ins of
    Push n -> modify (n :)
    Top n ->
      let top :: Int -> Stack -> Stack
          top i xs =
            let (as,bs) = splitAt i xs
            in head bs : as ++ tail bs
      in stackop n $ modify (top n)
    Add -> stackbinop (+)
    Div -> stackbinop div
    Dup -> stackop 1 $ modify (\(x:xs) -> x : x : xs)
    Emit ->
      stackop 1 $ get >>= \x -> liftIO (putChar $ chr $ fromIntegral $ head x)
    Mod -> stackbinop mod
    Mul -> stackbinop (*)
    Pow -> stackbinop (^)
    Fact ->
      let factorial n = product [1 .. n]
      in stackop 1 $ modify (\(x:xs) -> factorial x : xs)
    Pop -> stackop 1 $ modify tail
    Print -> stackop 1 $ get >>= \x -> liftIO (print $ head x)
    Read -> (evaluate . Push) =<< fmap read (liftIO getLine)
    Sub -> stackbinop (-)
    Swap -> stackop 2 $ modify (\(x:y:xs) -> y : x : xs)
    ShowStack -> get >>= liftIO . print