Reputation: 356
Let's imagine a dummy subset of Brainf*ck:
+
increments the counter
-
decrements the counter
A simple program:
program = "++++--" -- should evaluate to 2
And a stateful evaluation function:
eval :: Char -> State Int Char
eval '+' = do x <- get
put (x + 1)
return 'I'
eval '-' = do x <- get
put (x - 1)
return 'D'
How would you evaluate the program?
(Looks like a fold
to me but can't get my head around it, and it doesn't feel like it's the way to do it properly...)
Upvotes: 1
Views: 179
Reputation: 2223
An ugly solution but using the fold that you correctly suspected was applicable.
import Control.Monad.Trans.State
program = "++++--"
eval :: Char -> State Int Char
eval '+' = do
x <- get
put (x + 1)
return 'I'
eval '-' = do
x <- get
put (x - 1)
return 'D'
evalList :: [Char] -> State Int Char
evalList = foldl (\s c -> (s >> eval c)) (return ' ')
main = putStrLn $ show $ runState (evalList program) 0
Upvotes: 1
Reputation: 144126
You can use traverse_
from Data.Foldable
:
import Data.Foldable (traverse_)
execState (traverse_ eval "++++--") 0
Upvotes: 7
Reputation: 1059
The function you are looking for is sequence
, which has the signature sequence :: Monad m => [m a] -> m [a]
, and is a very common pattern when dealing with monads like State
.
For your code, you would expect the evaluator to look like this:
evalBF :: String -> State Int String
evalBF = sequence . map eval
Which you would then fully evaluate with something like:
main :: IO ()
main = do
src <- getLine
print $ runState (evalBF src) 0
Upvotes: 5