Kevin Meredith
Kevin Meredith

Reputation: 41939

Understanding State Monad's `get`

Given:

*Main> let s = state $ \x -> ("foo", x)
*Main> :t s
s :: MonadState s m => m [Char]

I tried to call get s, but got the below compile-time error:

*Main> :t get
get :: MonadState s m => m s

*Main> let x = get s

<interactive>:95:5: error:
    • Non type-variable argument
        in the constraint: MonadState t ((->) (m [Char]))
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        x :: forall s (m :: * -> *) t.
             (MonadState s m, MonadState t ((->) (m [Char]))) =>
             t

Then, I added that extension:

*Main> :set -XFlexibleContexts

But, it still does not compile:

*Main> let result = get s

<interactive>:9:5: error:
    • Could not deduce (MonadState s0 m0)
      from the context: (MonadState s m, MonadState t ((->) (m [Char])))
        bound by the inferred type for ‘result’:
                   (MonadState s m, MonadState t ((->) (m [Char]))) => t
        at <interactive>:9:5-18
      The type variables ‘s0’, ‘m0’ are ambiguous
    • In the ambiguity check for the inferred type for ‘result’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the inferred type
        result :: forall s (m :: * -> *) t.
                  (MonadState s m, MonadState t ((->) (m [Char]))) =>
                  t

Please explain why it's not compiling.

Upvotes: 0

Views: 132

Answers (2)

danidiaz
danidiaz

Reputation: 27766

The state in the state monad is like an underground river that follows the ostensible path of the computation. It hides the state when you don't need it and lets you focus on composing the (monadic) functions that form the computation.

get is like a well that taps into that river and lets you bring the state into the open when you need it. It is "part of the path you follow" so to speak, not some external function that you apply to the monadic actions.

Upvotes: 0

Zeta
Zeta

Reputation: 105925

Have a close look at the arrows. get does not take any argument:

get :: MonadState s m => m s
--     ^^^^^^^^^^^^^^
--     constraint, not type

Neither does s:

s :: MonadState s m => m [Char]
--   ^^^^^^^^^^^^^^
--   constraint, not type

We can combine those stateful computations with >>, since any MonadState s m is also a Monad:

setAndGet = s >> get

And we can have a look at the result of setAndGet with runState:

ghci> runState setAndGet "example"
("example","example")

Upvotes: 5

Related Questions