Custom MonadState instance

445 Views Asked by At

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
2

There are 2 best solutions below

3
On BEST ANSWER

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)

0
On

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) []