Question

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"
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top