I am trying to code runByte which executes a sequence of instructions and, when finished, returns the value at the top of the stack. If there is an error during execution returns Nothing. I have this Data type and function.
data Bytecode = PUSH Int
| ADD
| SUB
| MULT
| DIV
deriving (Eq, Show)
runBytecode :: [Bytecode] -> Maybe Int
runBytecode [PUSH x] = Just x
runBytecode [PUSH l, PUSH r, ADD] = ( ) <$> (runBytecode [PUSH l]) <*> (runBytecode [PUSH r])
runBytecode [PUSH l, PUSH r, SUB] = (-) <$> (runBytecode [PUSH l]) <*> (runBytecode [PUSH r])
runBytecode [PUSH l, PUSH r, DIV] = (div) <$> (runBytecode [PUSH l]) <*> (runBytecode [PUSH r])
runBytecode [PUSH l, PUSH r, MULT] = (*) <$> (runBytecode [PUSH l]) <*> (runBytecode [PUSH r])
It works when I try make a single operation like runBytecode [PUSH 1, PUSH 2, ADD]
but when I try multiple operations runBytecode [PUSH 1, PUSH 4, PUSH 9, MULT, ADD]
I get Non-exhaustive patterns, how can I change my pattern matching to all these cases?
CodePudding user response:
You list expressions only work on lists with exactly one or three elements. You should work with a stack such that items are pushed on the stack, and then popped and the result is pushed, so:
runBytecode :: [Bytecode] -> Maybe Int
runBytecode = go []
where go (x:_) [] = Just x
go xs (PUSH x:ys) = go (x:xs) ys
go (x1:x2:xs) (ADD:ys) = go (x1 x2:xs) ys
# ⋮
go _ _ = Nothing
Here we thus use as pattern (x1:x2:xs)
and (ADD:ys)
: this will match a non-empty list with ADD
as first item, but xs
is a list with an arbitrary number of remaining elements.