Usage of runRVar over some monad transformer stack - haskell

In the following example:
toss :: Double -> RVar Bool
toss p = do
q <- uniform 0 1
return $ q <= p
toss' :: MonadRandom m => Double -> m Bool
toss' p = runRVar (toss p) StdRandom
foo :: StateT Int RVar ()
foo = do
h <- lift $ toss' 0.5
if h then put 100 else put 0
bar :: StateT Int RVar ()
bar = do
h <- lift $ toss 0.5
if h then put 404 else put 200
testFoo :: MonadRandom m => m ((), Int)
testFoo = runRVar (runStateT foo 0) StdRandom
testBar :: MonadRandom m => m ((), Int)
testBar = runRVar (runStateT bar 0) StdRandom
I am confused about:
why the signature of foo is forced to be StateT Int RVar () even though toss' has signature m Bool for some MonadRandom m
Why testFoo has to be run with some StdRandom even though toss' already runRVar with StdRandom. It makes sense from a type perspective, but which StdRandom end up being used? If this question makes any sense at all.
Would it be possible to rewrite foo's signature as MonadRandom m => StateT Int m ()

When monomorphism restriction is on (it's on by default), all types of top-level binders will be inferred monomorphic.
You should add RVar to the monad stack like you did in bar. MonadRandom is too general.
StdRandom is just a data constructor, so it has no specific state. random-fu should handle updating state automatically.
Just add the signature. See 1.

Related

Using MonadRandom with MonadState

I have this bit of code:
import Data.Random
import Control.Monad.State
foo :: s -> StateT s RVar ()
foo s = do
p <- lift $ (uniform 0 1 :: RVar Double)
if p > 0.5 then put s else return ()
And I would like to refactor its signature to be of form:
foo :: (MonadState s m, RandomSource m s) => s -> m ()
I thought I could equip RVar with MonadState functions:
{- LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
instance MonadState s m => MonadState s (RVarT m) where
get = lift get
put = lift . put
state = lift . state
and write:
foo :: (MonadState s m, RandomSource m s) => s -> m ()
foo s = do
p <- (uniform 0 1 :: RVar Double)
if p > 0.5 then put s else return ()
But I am getting this inexplicable error:
Couldn't match type ‘m’
with ‘t0 (RVarT Data.Functor.Identity.Identity)’
‘m’ is a rigid type variable bound by
the type signature for
foo :: (MonadState s m, RandomSource m s) => s -> m ()
at ApproxMedian.hs:99:8
Expected type: m Double
Actual type: t0 (RVarT Data.Functor.Identity.Identity) Double
Relevant bindings include
foo :: s -> m () (bound at ApproxMedian.hs:100:1)
In a stmt of a 'do' block: p <- lift $ (uniform 0 1 :: RVar Double)
In the expression:
do { p <- lift $ (uniform 0 1 :: RVar Double);
if p > 0.5 then put s else return () }
In an equation for ‘foo’:
foo s
= do { p <- lift $ (uniform 0 1 :: RVar Double);
if p > 0.5 then put s else return () }
Failed, modules loaded: Core, Statistics.
Please explain the error and help make the more generic signature possible?
If I wanted to do:
foo :: (MonadRandom m, MonadState s m) => s -> m ()
How would I implement it? I cannot use uniform any more. Because it locks me to signature RVar a but I really want MonadRandom m => m a,
or at the very least Monad m => RVarT m a
uniform is not polymorphic in the monad it runs in (in other words, you can't run it in any choice of m if all you know is that RandomSource m s):
uniform :: Distribution Uniform a => a -> a -> RVar a
However, if you have a source of entropy, you can runRVar it in any m if RandomSource m s:
runRVar :: RandomSource m s => RVar a -> s -> m a
which means you can write foo with your desired type signature as
foo :: (MonadState s m, RandomSource m s) => s -> m ()
foo s = do
p <- runRVar (uniform 0 1 :: RVar Double) s
when (p > 0.5) $ put s

Types in MaybeT computation

Working in an IO computation I ended up with a staircase of case mbValue of …s and figured out that I should use the Maybe monad to simplify the code. Since it's within an IO computation and I need to get IO values, I used the MaybeT monad transformer so that I can lift IO computation into Maybe.
Now, I have always thought about values being “stripped” of their Maybeness after an values <- mbValue inside a Maybe computation, but this turns out to be too simple of a heuristic here.
As highlighted below, when using a Maybe a value as an a (here by passing it to read), it fails to type check:
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (runMaybeT)
lol :: IO (Maybe Int)
lol = return (Just 3)
lal :: IO (Maybe String)
lal = return (Just "8")
foo :: IO (Maybe Bool)
foo = do
b <- runMaybeT $ do
x <- lift lol
y <- lift lal
return (x < (read y))
return b ^-- Couldn't match type ‘Maybe String’ with ‘String’
main = foo >>= print
If I put a typed hole in for return (x < (read y)), I see that it expects a Bool, which makes sense, but also that the current bindings include
|| y :: Data.Maybe.Maybe GHC.Base.String
|| (bound at /private/tmp/test.hs:14:5)
|| x :: Data.Maybe.Maybe GHC.Types.Int
|| (bound at /private/tmp/test.hs:13:5)
I.e., y is a Maybe String. This of course explains the error, but I'm left confused. Where is my understanding wrong, and how can I fix this error?
In short: Replace lift by the MaybeT constructor.
Note that
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
and
lift :: (MonadTrans t, Monad m) => m a -> t m a
Your use of lift in
x <- lift lol
is at the type
lift :: IO (Maybe Int) -> MaybeT IO (Maybe Int)
That's why x will be a Maybe Int again. The lift adds a fresh MaybeT layer that is independent of the Maybe occurrence you already have.
But
MaybeT :: m (Maybe a) -> MaybeT m a
instead as in
x <- MaybeT lol
will be used at type
MaybeT :: IO (Maybe a) -> MaybeT IO a
and do the right thing.
When specialized to MaybeT, lift :: Monad m => m a -> MaybeT m a. Since lol :: IO (Maybe Int), m is IO and a is Maybe Int, therefore lift lol :: MaybeT IO (Maybe Int).
IO (Maybe a) is just the value contained within a MaybeT IO a newtype wrapper, so there's no need to lift it; instead use the MaybeT constructor, for example as in MaybeT lol.
But this is not how people tend to use monad transformers. Instead, just use MaybeT values and lift as needed:
import Control.Monad
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (runMaybeT, MaybeT)
lol :: MaybeT IO Int
lol = return 3
lal :: MaybeT IO String
lal = return "8"
foo :: IO (Maybe Bool)
foo =
runMaybeT $ do
x <- lol
y <- lal
_ <- lift getLine -- lift (IO String) to MaybeT IO String
_ <- return 100 -- lift any pure value
_ <- mzero -- use the MonadPlus instance to get a lifted Nothing.
return (x < (read y))
main = foo >>= print

Is it possible to emulate the behaviour of StateT without the use of custom types?

If we have the following two functions, add and subtract, it is simple to chain them to run a series of calculations on an input:
add :: Int -> State Int ()
add n = state $ \x -> ((),x+n)
subtract :: Int -> State Int ()
subtract n = state $ \x -> ((),x-n)
manyOperations :: State Int ()
manyOperations = do
add 2
subtract 3
add 5
--etc
result = execState manyOperations 5
--result is 9
If we want to print out the state after each calculation is done, we use the StateT monad transformer:
add :: Int -> StateT Int IO ()
add n = StateT $ \x -> print (x+n) >> return ((),x+n)
subtract :: Int -> StateT Int IO ()
subtract n = StateT $ \x -> print (x-n) >> return ((),x-n)
manyOperations :: StateT Int IO ()
manyOperations = do
add 2
subtract 3
add 5
main = runStateT manyOperations 5
-- prints 7, then 4, then 9
Is it possible to replicate this "combined computation and printing" without StateT or any custom datatypes?
As far as I know it's possible to do all the processes that MaybeT IO a can do using IO (Maybe a), but it seems like that's because it's just nested monads. On the other hand, StateT might not have an alternative because s -> (a,s) is fundamentally different to s -> m (a,s)
I can only see two directions the code could go: using State Int (IO ()) or IO (State Int ()), but both of these seem nonsensical given the implementation of StateT
I believe it is impossible. Am I correct?
Note: I know this is completely impractical, but I couldn't find any solution after some hours of work, which means I'm correct or my skills aren't enough for the task.
Of course you can do all the plumbing yourself. Monads don't add anything new to Haskell, they just enable a ton of code reuse and boilerplate reduction. So anything you can do with a monad, you can laborously do by hand.
manyOperations :: Int -> IO ()
manyOperations n0 = do
let n1 = n0 + 2
print n1
let n2 = n1 - 3
print n2
let n3 = n2 + 5
print n3
If the amount of repetition in the above function is too much for you (it is for me!) you could try to reduce it with a 'combined computation and printing' function but at this point you're bending over backwards to avoid StateT.
-- a bad function, never write something like this!
printAndCompute :: a -> (a -> b) -> IO b
printAndCompute a f = let b = f a in print b >> return b
-- seriously, don't do this!
manyOperations n0 = do
n1 <- printAndCompute (+2) n0
n2 <- printAndCompute (-3) n1
n3 <- printAndCompute (+5) n2
return ()
I'm not sure if this is quite what you're looking for, but you could define an operation which takes a stateful operation that you alread have, and prints out the state after performing the operation -
withPrint :: (Show s) => State s a -> StateT s IO a
withPrint operation = do
s <- get
let (a, t) = runState operation s
liftIO (print t)
put t
return a
and then do
manyOperations :: StateT Int IO ()
manyOperations = do
withPrint (add 2)
withPrint (subtract 3)
withPrint (add 5)
-- etc
This doesn't avoid using StateT but it abstracts out the conversion of your regular, non-IO state operations into IO-ful state operations so you don't have to worry about the details (aside from adding withPrint when you want the state to be printed.
If you don't want the state printed for a particular operation, you could define
withoutPrint :: State s a -> StateT s IO a
withoutPrint operation = do
s <- get
let (a, t) = runState operation s
put t
return a
which is actually equivalent to
import Control.Monad.Morph
withoutPrint :: State s a -> StateT s IO a
withoutPrint = hoist (\(Identity a) -> return a)
using hoist from Control.Monad.Morph to transform the monad underlying StateT from Identity to IO.
You can completely avoid those data types by using s -> IO (a, s) directly, substituting for a and s appropriately. It definitely won't be as nice though.
It would look something like this:
-- This makes StateIO s act as a shorthand for s -> IO (a, s)
type StateIO s a = s -> IO (a, s)
add :: Int -> StateIO Int ()
add n = \x -> print (x+n) >> return ((),x+n)
sub :: Int -> StateIO Int ()
sub n = \x -> print (x-n) >> return ((),x-n)
manyOperations :: StateIO Int ()
manyOperations = -- Using the definition of (>>=) for StateT
\s1 -> do -- and removing a lambda that is immediately applied
(a, s2) <- add 2 s1
(a, s3) <- sub 3 s2
add 5 s3
result :: IO ((), Int)
result = manyOperations 5
The state has to be explicitly threaded through all the operations. This is a major gain we get from using the StateT datatype: the (>>=) method of its Monad instance does all this for us! We can see from this example, though, that there is nothing magical going on in StateT. It's just a very nice way of abstracting out the threading of state.
Also, the relationship between StateT and State is the opposite of the relationship between MaybeT and Maybe: State is defined in terms of StateT. We can see that fact expressed in this type synonym:
type State s = StateT s Identity
It is a transformer over the Identity type (which has the trivial Monad instance).

State's `put` and `get` functions

I'n looking at the State Monad's put and get:
ghci> :t get
get :: MonadState s m => m s
ghci> :t runState
runState :: State s a -> s -> (a, s)
ghci> runState get [1,2,3]
([1,2,3],[1,2,3])
In get's type signature: MonadState s m => m s, how does [1,2,3] have a type of MonadState s m? It's not clear to me what the types of s and m are.
Also, can you please say more as to how to use put?
ghci> :t put
put :: MonadState s m => s -> m ()
Overall, it seems that I don't understand what MonadState s m is. Could you please explain with put and get examples?
MonadState s m is a typeclass constraint, not a type. The signature:
get :: MonadState s m => m s
Says that for some monad m storing some state of type s, get is an action in m that returns a value of type s. This is pretty abstract, so let’s make it more concrete with the less-overloaded version of State from transformers:
get :: State s s
put :: s -> State s ()
Now say we want to use State to keep a simple counter. Let’s use execState instead of runState so we can just pay attention to the final value of the state. We can get the value of the counter:
> execState get 0
0
We can set the value of the counter using put:
> execState (put 1) 0
1
We can set the state multiple times:
> execState (do put 1; put 2) 0
2
And we can modify the state based on its current value:
> execState (do x <- get; put (x + 1)) 0
1
This combination of get and put is common enough to have its own name, modify:
> execState (do modify (+ 1)) 0
1
> execState (do modify (+ 2); modify (* 5)) 0
10
MonadState is the class of types that are monads with state. State is an instance of that class:
instance MonadState s (State s) where
get = Control.Monad.Trans.State.get
put = Control.Monad.Trans.State.put
So are StateT (the state monad transformer, which adds state to another monad) and various others. This overloading was introduced so that if you’re using a stack of monad transformers, you don’t need to explicitly lift operations between different transformers. If you’re not doing that, you can use the simpler operations from transformers.
Here’s another example of how to use State to encapsulate a map of variables with Data.Map:
import Control.Monad.Trans.State
import qualified Data.Map as M
action = do
modify (M.insert "x" 2) -- x = 2
modify (M.insert "y" 3) -- y = 3
x <- gets (M.! "x")
y <- gets (M.! "y")
modify (M.insert "z" (x + y)) -- z = x + y
modify (M.adjust (+ 2) "z") -- z += 2
gets (M.! "z") -- return z
main = do
let (result, vars) = execState action M.empty
putStr "Result: "
print result
putStr "Vars: "
print vars
In get's type signature: MonadState s m => m s, how does [1,2,3] have
a type of MonadState s m? It's not clear to me what the types of s and
m are.
ghci> runState get [1,2,3]
The function runState takes two arguments: the first is the State action to run, and the second is the initial state. So, since the initial state is [1,2,3] which is a list of integers (*), the state type s is just [Integer].
(*) Actually, [1,2,3] :: Num a => [a] before GHCi defaults it, but for simplicity's sake let's use [Integer] as GHCi does.
Hence, we see that runState is specialized to
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
Now, about the first argument:
get :: MonadState s m => m s
We must have m s = State s a because we are passing it to runState which requires such type. Hence:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState s m => m s
with m s = State [Integer] a
The latter equation can be simplified as follows:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState s m => m s
with m = State [Integer]
and s = a
Substituting s:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState a m => m a
with m = State [Integer]
Substituting m:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState a (State [Integer]) => State [Integer] a
Now, the constraint MonadState a (State [Integer]) is satisfied only when a = [Integer]. This is tricky to see, since the MonasState type class exploits a functional dependency to enforce that every monad in that class has only one related state type. This is also made more complex from State being a wrapper around StateT. Anyway, we get:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState a (State [Integer]) => State [Integer] a
with a = [Integer]
So,
runState :: State [Integer] [Integer] -> [Integer] -> ([Integer], [Integer])
get :: MonadState [Integer] (State [Integer]) => State [Integer] [Integer]
And since the constraint is satisfied:
runState :: State [Integer] [Integer] -> [Integer] -> ([Integer], [Integer])
get :: State [Integer] [Integer]
And now we can see the involved ground types.

Combine state with IO actions

Suppose I have a state monad such as:
data Registers = Reg {...}
data ST = ST {registers :: Registers,
memory :: Array Int Int}
newtype Op a = Op {runOp :: ST -> (ST, a)}
instance Monad Op where
return a = Op $ \st -> (st, a)
(>>=) stf f = Op $ \st -> let (st1, a1) = runOp stf st
(st2, a2) = runOp (f a1) st1
in (st2, a2)
with functions like
getState :: (ST -> a) -> Op a
getState g = Op (\st -> (st, g st)
updState :: (ST -> ST) -> Op ()
updState g = Op (\st -> (g st, ()))
and so forth. I want to combine various operations in this monad with IO actions. So I could either write an evaluation loop in which operations in this monad were performed and an IO action is executed with the result, or, I think, I should be able to do something like the following:
newtype Op a = Op {runOp :: ST -> IO (ST, a)}
Printing functions would have type Op () and other functions would have type Op a, e.g., I could read a character from the terminal using a function of type IO Char. However, I'm not sure what such a function would look like, since e.g., the following is not valid.
runOp (do x <- getLine; setMem 10 ... (read x :: Int) ... ) st
since getLine has type IO Char, but this expression would have type Op Char. In outline, how would I do this?
Use liftIO
You're already very close! Your suggestion
newtype Op a = Op {runOp :: ST -> IO (ST, a)}
is excellent and the way to go.
To be able to execute getLine in an Op context, you need to 'lift' the IO operation into the Op monad. You can do this by writing a function liftIO:
liftIO :: IO a -> Op a
liftIO io = Op $ \st -> do
x <- io
return (st, x)
You can now write:
runOp (do x <- liftIO getLine; ...
Use class MonadIO
Now the pattern of lifting an IO action into a custom monad is so common that there is a standard type class for it:
import Control.Monad.Trans
class Monad m => MonadIO m where
liftIO :: IO a -> m a
So that your version of liftIO becomes an instance of MonadIO instead:
instance MonadIO Op where
liftIO = ...
Use StateT
You've currently written your own version of the state monad, specialised to state ST. Why don't you use the standard state monad? It saves you from having to write your own Monad instance, which is always the same for the state monad.
type Op = StateT ST IO
StateT already has a Monad instance and a MonadIO instance, so you can use those immediately.
Monad transformers
StateT is a so-called monad transformer. You only want IO actions in your Op monad, so I've already specialized it with the IO monad for you (see the definition of type Op). But monad transformers allow you to stack arbitrary monads. This what intoverflow is talking about. You can read more about them here and here.
The basic approach would be to rewrite your Op monad as a monad transformer. This would allow you to use it in a "stack" of monads, the bottom of which might be IO.
Here's an example of what that might look like:
import Data.Array
import Control.Monad.Trans
data Registers = Reg { foo :: Int }
data ST = ST {registers :: Registers,
memory :: Array Int Int}
newtype Op m a = Op {runOp :: ST -> m (ST, a)}
instance Monad m => Monad (Op m) where
return a = Op $ \st -> return (st, a)
(>>=) stf f = Op $ \st -> do (st1, a1) <- runOp stf st
(st2, a2) <- runOp (f a1) st1
return (st2, a2)
instance MonadTrans Op where
lift m = Op $ \st -> do a <- m
return (st, a)
getState :: Monad m => (ST -> a) -> Op m a
getState g = Op $ \st -> return (st, g st)
updState :: Monad m => (ST -> ST) -> Op m ()
updState g = Op $ \st -> return (g st, ())
testOpIO :: Op IO String
testOpIO = do x <- lift getLine
return x
test = runOp testOpIO
The key things to observe:
The use of the MonadTrans class
The use of the lift function acting on getLine, which is used to bring the getline function from the IO monad and into the Op IO monad.
Incidentally, if you don't want the IO monad to always be present, you can replace it with the Identity monad in Control.Monad.Identity. The Op Identity monad behaves exactly the same as your original Op monad.

Resources