When I do:
cabal sandbox init
cabal update
cabal install hakaru
cabal repl
λ> :l simple.hs
λ> sample test []
with simple.hs containing:
{-# LANGUAGE MultiParamTypeClasses #-}
import Language.Hakaru.ImportanceSampler
import Control.Monad.State
instance MonadState Int Measure
test :: Measure Int
test = put 1 >> get >>= \i -> return i
my computer runs out of memory.
How can I successfully make the Measure monad an instance of MonadState (i.e. have test above return 1)? The Measure type is already an instance of Monad with bind and return defined. Is there some default way I can define MonadState's put and get in terms of lift, bind, and return to make it work? I tried:
get = lift get
put = lift . put
but I couldn't get the (transformer?) types to work out:
simple.hs:6:9:
Couldn't match type ‘t0 m0’ with ‘Measure’
Expected type: Measure Int
Actual type: t0 m0 Int
In the expression: lift get
In an equation for ‘get’: get = lift get
simple.hs:7:9:
Couldn't match type ‘t1 m1’ with ‘Measure’
Expected type: m1 () -> Measure ()
Actual type: m1 () -> t1 m1 ()
In the first argument of ‘(.)’, namely ‘lift’
In the expression: lift . put
Measure is already defined in a following way:
newtype Measure a = Measure { unMeasure :: [Cond] -> Sampler (a, [Cond]) }
You can see that there is no place to store your Int, so you cannot make it a proper instance of MonadState.
If you want to extend Measure to MonadState, you can use StateT monad transformer:
test :: StateT Int Measure Int
test = put 1 >> get >>= \i -> return i
What happened here? StateT s is a monad transformer, which lets you to combine State s monad with any other monad (in this example Measure)
The exact code which ended up working for me is:
import Language.Hakaru.ImportanceSampler
import Language.Hakaru.Distribution
import Control.Monad.State
import System.IO.Unsafe (unsafePerformIO)
test1 :: StateT Int Measure Int
test1 = do
i <- lift $ unconditioned $ categorical [(0,0.25), (1,0.25), (2,0.5)]
j <- lift $ unconditioned $ categorical [(i,0.25), (1,0.25), (2,0.5)]
put (i + j)
k <- get
return k
run_test1 = unsafePerformIO $ empiricalMeasure 10 (evalStateT test1 0) []
Related
I am writing a Sudoku generator/solver in Haskell as a learning exercise.
My solve function takes in a UArray but returns a State Int (UArray ...) so that it can also return the maximum difficulty level that it found while solving.
This is my function so far (still in the very experimental early stage):
import Control.Monad.State (State, put)
import Control.Monad.Trans.Class (lift)
import Data.Array.MArray (thaw)
import Data.Array.ST (runSTUArray)
import Data.Array.Unboxed (UArray)
-- ...
type Cell = Word16
solve :: UArray (Int, Int) Cell -> State Int (UArray (Int, Int) Cell)
solve grid = do
return $ runSTUArray $ do
arr <- thaw grid
lift $ put 42
return arr
It does not really do anything with the mutable array yet. I am simply trying to get it to type check with the put 42, but currently get the following error:
• Couldn't match kind ‘*’ with ‘* -> *’
When matching the kind of ‘ST’
• In a stmt of a 'do' block: lift $ put 42
In the second argument of ‘($)’, namely
‘do arr <- thaw grid
lift $ put 42
return arr’
In the second argument of ‘($)’, namely
‘runSTUArray
$ do arr <- thaw grid
lift $ put 42
return arr’
|
128 | lift $ put 42
| ^^^^^^^^^^^^^
runSTUArray ... is a pure value, it does not know anything about "outer monad". And State cares about how you use it, you cannot pass it opaquely into ST.
What you could do:
Option1: change the whole program to move more logic to ST side. Instead of State you'd use STRef then:
solve :: ST s (STRef Int) -> ST s (UArray (Int, Int) Cell) -> ST s ()
...
Option2: manually extract it and pass it to ST, then get back and put explicitly. But there is complication. runSTUArray does not allow getting another value together with the array. I don't know how it can be done safely with current array functions. Unsafely you could re-implement better runSTUArray which can pass another value. You could also add fake cells and encode the new state there.
The way to export another value exists in the vector package, there is (in new versions) createT function which can take not bare vector but a structure containing it (or even several vectors). So, overall, your example would be like:
import Control.Monad.State (State, put, get)
import Data.Word (Word16)
import qualified Data.Vector.Unboxed as DVU
type Cell = Word16
solve :: DVU.Vector Cell -> State Int (DVU.Vector Cell)
solve grid = do
oldState <- get
let (newState, newGrid) = DVU.createT (do
arr <- DVU.thaw grid
pure (oldState + 42, arr))
put newState
pure newGrid
vectors are one-dimensional only, unfortunately
solve grid has form return $ .... This means that State Int (UArray (Int, Int) Cell) is just specialized Monad m => m (UArray (Int, Int) Cell) - the ... does not have access to the features of this specific monad, it's just a UArray (Int, Int) Cell value that you return.
I was able to get a slight variation to compile and run after changing the State monad to a tuple (Int, Grid):
import Control.Monad.ST (ST, runST)
import Data.Array.MArray (freeze, thaw, writeArray)
import Data.Array.ST (STUArray)
import Data.Array.Unboxed (UArray)
import Data.Word (Word16)
type Cell = Word16
type Grid = UArray (Int, Int) Cell
solve :: Grid -> (Int, Grid)
solve grid =
runST $ do
mut <- thaw grid :: ST s (STUArray s (Int, Int) Cell)
writeArray mut (0, 0) 0 -- test that I can actually write
frozen <- freeze mut
return (42, frozen)
This works fine for my application.
I want to take a weighted sample from a list inside a monad transformer stack.
I've managed to get this minimal example to type-check, but I don't understand the error message I get upon running main, and I don't know how to fix it.
{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts #-}
module Testing where
import Control.Monad.IO.Class (liftIO, MonadIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State.Lazy (modify, runStateT, StateT)
import Control.Monad.Trans.Reader (ask, runReaderT, ReaderT)
import Data.Random
import Data.Random.Distribution.Uniform.Exclusive (Excludable)
import Data.Random.Shuffle.Weighted (weightedSample)
testS :: [(Int, Int)]
testS = [(1,c) | c <- [11..20]]
loop :: (Num w, Ord w, Show a, MonadIO m, Excludable w, Distribution Uniform w, MonadRandom (StateT [[a]] m)) => ReaderT [(w, a)] (StateT [[a]] m) ()
loop = do
s <- ask
a <- lift $ sample $ weightedSample 1 s
liftIO $ print a
lift $ modify ((:) a)
main :: (MonadIO m, MonadRandom (StateT [[Int]] m)) => m ((), [[Int]])
main = runStateT (runReaderT loop testS) []
The actual program is supposed to help with learning by selecting a random question from the initial config (testS), and then update the weights in the state so that questions the user got wrong become more likely.
Here is the error I get when running main in ghci:
No instance for (random-source-0.3.0.6:Data.Random.Internal.Source.MonadRandom
(Control.Monad.Trans.State.Lazy.StateT [[Int]] m0))
arising from a use of `main'
Possible fix:
add an instance declaration for
(random-source-0.3.0.6:Data.Random.Internal.Source.MonadRandom
(Control.Monad.Trans.State.Lazy.StateT [[Int]] m0))
In the expression: main
In an equation for `it': it = main
I can't seem to get random-fu installed to test, but based on browsing documentation I still have a guess that might be right.
The line
a <- lift $ sample $ weightedSample 1 s
Tries to run sample $ weightedSample 1 s in the underlying monad
StateT [[Int]] IO
However, StateT monads are only MonadRandoms when their state is one of the supported random number generator states.
You probably want to run it in IO, which is itself a MonadRandom.
In other words, add another lift.
BTW if this is right, the reason why it still typechecks initially is that you could in theory add an instance for StateT [[Int]] IO if you wanted. (But you probably don't.)
In the following code, how can I replace put 1 with some code that insert nondeterministically 1 or 2 in the state?
import Control.Monad.List
import Control.Monad.Trans.State
test :: StateT Int [] Int
test = do
put 1
v <- get
return v
Your monad stack signature is already the correct one.
Lift a computation from the [] monad and bind to its value. This will fork the computation:
test :: StateT Int [] Int
test = do
s <- lift [1,2,3]
put s
v <- get
return v
Testing to see it works:
*Main> runStateT test 10
[(1,1),(2,2),(3,3)]
Not only there are many results, but the state gets included in the nondeterminism as well.
If test had had type ListT (State Int) Int, only the results would have been nondetermistic, the state would have been shared among all the branches in the computation:
test :: ListT (State Int) Int
test = do
s <- ListT $ return [1,2,3]
put s
v <- get
return v
The result:
*Main> runState (runListT test) 10
([1,2,3],3)
maybe you want something like this instead:
import Control.Monad.List
import Control.Monad.Trans.State
import System.Random (randomIO)
test :: StateT Int IO Int
test = do
put1 <- liftIO $ randomIO
put (if put1 then 1 else 2)
v <- get
return v
This will use the global generator to set 1 or 2 at random
1) I need to pass a field constructor parameter to a function. I made some tests but i was unable to do so. Is it possible? Otherwise, is it possible with lens package?
2) Is it possible in a MonadState to modify a field using modify? (I made a few attempts, but without success. For example: modify (second = "x") does not work.
import Control.Monad.State
data Test = Test {first :: Int, second :: String} deriving Show
dataTest = Test {first = 1, second = ""}
test1 = runStateT modif1 dataTest -- OK
test2 = runStateT (modif2 "!") dataTest -- OK
test3 = runStateT (modif3 second) dataTest -- WRONG
-- modif1 :: StateT Test IO ()
modif1 = do
st <- get
r <- lift getLine
put $ st {second = "x" ++ r}
-- modif2 :: String -> StateT Test IO ()
modif2 s = do
stat <- get
r <- lift getLine
put $ stat {second = "x" ++ r ++ s}
-- modif3 :: ???? -> StateT Test IO ()
modif3 fc = do
stat <- get
r <- lift getLine
put $ stat {fc = "x" ++ r}
-- When i try to load the module, this is the result:
-- ghc > Failed:
-- ProvaRecord.hs:33:16:`fc' is not a (visible) constructor field name
As you said, you're probably looking for lenses. A lens is a value that allows to read, set or modify a given field. Usually with Control.Lens, you define fields with underscores and you use makeLenses to create full-featured lenses.
There are many combinators that allow lenses to be used together within MonadState. In your case we can use %=, which in this case would be specialized to type
(MonadState s m) => Lens' s b -> (b -> b) -> m ()
which modifies a state value using a given lens and a function that operates on the inside value.
Your example could be rewritten using lenses as follows:
{-# LANGUAGE TemplateHaskell, RankNTypes #-}
import Control.Lens
import Control.Monad.State
data Test = Test { _first :: Int
, _second :: String
}
deriving Show
-- Generate `first` and `second` lenses.
$(makeLenses ''Test)
-- | An example of a universal function that modifies any lens.
-- It reads a string and appends it to the existing value.
modif :: Lens' a String -> StateT a IO ()
modif l = do
r <- lift getLine
l %= (++ r)
dataTest :: Test
dataTest = Test { _first = 1, _second = "" }
test :: IO Test
test = execStateT (modif second) dataTest
I have the following code:
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.State
type T = StateT Int IO Int
someMaybe = Just 3
f :: T
f = do
x <- get
val <- lift $ do
val <- someMaybe
-- more code in Maybe monad
-- return 4
return 3
When I use do notation inside to work in Maybe monad it fails. From the error it gives it looks like type signature for this do doesn't match. However I have no idea how to fix it. I tried some lift combinations, but none of them worked and I don't want to guess anymore.
The problem is that Maybe is not part of your transformer stack. If your transformer only knows about StateT Int and IO, it does not know anything about how to lift Maybe.
You can fix this by changing your type T to something like:
type T = StateT Int (MaybeT IO) Int
(You'll need to import Control.Monad.Trans.Maybe.)
You will also need to change your inner do to work with MaybeT rather than Maybe. This means wrapping raw Maybe a values with MaybeT . return:
f :: T
f = do
x <- get
val <- lift $ do
val <- MaybeT $ return someMaybe
-- more code in Maybe monad
return 4
return 3
This is a little awkward, so you probably want to write a function like liftMaybe:
liftMaybe = MaybeT . return
If you used lift to lift IO a values in other parts of your code, this will now break because you have three levels in your transformer stack now. You will get an error that looks like this:
Couldn't match expected type `MaybeT IO t0'
with actual type `IO String'
To fix this, you should use liftIO for all your raw IO a values. This uses a typeclass to life IO actions through any number of transformer layers.
In response to your comment: if you only have a bit of code depending on Maybe, it would be easier just to put the result of the do notation into a variable and match against that:
let maybeVal = do val <- someMaybe
-- more Maybe code
return 4
case maybeVal of
Just res -> ...
Nothing -> ...
This means that the Maybe code will not be able to do an IO. You can also naturally use a function like fromMaybe instead of case.
If you want to run the code in the inner do purely in the Maybe monad, you will not have access to the StateT Int or IO monads (which might be a good thing). Doing so will return a Maybe value, which you will have to scrutinize:
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.State
type T = StateT Int IO Int
someMaybe = Just 3
f :: T
f = do
x <- get
-- no need to use bind
let mval = do
-- this code is purely in the Maybe monad
val <- someMaybe
-- more code in Maybe monad
return 4
-- scrutinize the resulting Maybe value now we are back in the StateT monad
case mval of
Just val -> liftIO . putStrLn $ "I got " ++ show val
Nothing -> liftIO . putStrLn $ "I got a rock"
return 3