I am learning Haskell now, and I am trying to work with the state Monad.
I am recursively asking for input from the user and append it to the list. When I am implementing the IO handling and state execution in the same function, the program works as expected:
import Control.Monad.State
push :: String -> State [String] ()
push a = state $ \xs -> ((),a:xs)
testingState :: State [String] ()
testingState = do
push ("testing state!")
return ()
handleState :: [String] -> IO()
handleState previousStack = do
line <- getLine
let userIntput = words line
let stack = userIntput ++ previousStack
let newStack = (execState testingState) stack
handleState newStack
main :: IO
main = do
handleState []
For reasons I don't understand, when I am separating the state handling function from the IO function, the returned state is wrapped with a list:
handleState :: [String] -> IO()
handleState previousStack = do
line <- getLine
let newStack = changeState line stack
handleState newStack
changeState :: String -> [String] -> [String]
changeState line previousStack = do
let userIntput = words line
let stack = userIntput ++ previousStack
let newStack = (execState testingState) stack
return newStack
main = do
handleState []
The following code gives me a compiler error that the actually returned type is a nested list:
• Couldn't match type ‘[Char]’ with ‘Char’
Expected type: [String]
Actual type: [[String]]
Also, I can only flatten the array outside of changeState function, doing it inside the function would not work.
Anyone could explain why this is happening? and a better way of handling state in a recursive function?
You are using a
doin andreturnin thechangeState. Since the type of thedoblock is[String], it will make use of a the list instance of theMonadtypeclass, and this thus means thatreturn :: Monad m => a -> m awill wrap an element in a list.You can implement you
changeStatefunction as: