I'm new to Monads and Haskell in general and trying to understand how to return a value when using them. My code looks something like the following:
foo :: A -> B
foo a = do b <- fooC a (C 0)
-- want to return just (B "b")
fooC :: A -> C -> State MyState B
fooC a c = return (B "b")
I tried using snd (snd b)
, but apparently State MyState B
is not a tuple? How can I return the desired value (B "b")
?
Edit: Taking Daniel's advice into account, the rewrite looks like this:
data MyState = MyState String
data C = C Int
foo :: String -> String
-- want to return just "b"
foo a = evalState (fooC a) (C 0)
fooC :: String -> Int -> State MyState String
fooC a c = return "b"
That still results in a compilation error:
Couldn't match expected type `State s0 String'
with actual type `Int -> State MyState String'
In the return type of a call of `fooC'
Probable cause: `fooC' is applied to too few arguments
In the first argument of `evalState', namely `(fooC a)'
In the expression: evalState (fooC a) (C 0)
Edit 2: Fixed! Final version looks as follows:
import Control.Monad.State
data MyState = MyState String
data C = C Int
foo :: String -> String
-- want to return just (B "b")
foo a = evalState (fooC a (C 0)) (MyState "whatever")
fooC :: String -> C -> State MyState String
fooC a c = return "b"
main = print(foo("test"))
-- prints "b"
What you need is
foo a = evalState (fooC a (C 0)) (MyState "whatever")
You construct the State MyState B
action fooC a (C 0)
, unwrap it to get a function, and apply that function to an initial state. Since the state isn't used in this example, you could here also use undefined
instead of MyState "whatever"
, but in general, you need to provide a meaningful initial state.
State MyState B
is not a tuple, it is isomorphic to a function
MyState -> (B, MyState)
but that function is wrapped in a newtype
(details vary by monad transformer library package and version), so to access the result of that function applied to an initial state, you need an unwrapping function. For State
, there are
runState :: State s r -> (s -> (r,s))
which gives you the function returning the pair,
evalState :: State s r -> (s -> r)
that gives you the function composed with fst
, so the final state is discarded, and
execState :: State s r -> (s -> s)
that composes the function with snd
, so only the final state is returned.