Пользовательский экземпляр MonadState

Когда я делаю:

cabal sandbox init
cabal update
cabal install hakaru
cabal repl
λ> :l simple.hs 
λ> sample test []

с simple.hs, содержащим:

{-# LANGUAGE MultiParamTypeClasses #-}
import Language.Hakaru.ImportanceSampler
import Control.Monad.State
instance MonadState Int Measure
test :: Measure Int
test = put 1 >> get >>= \i -> return i

моему компьютеру не хватает памяти.

Как я могу успешно сделать монаду Measure экземпляром MonadState (т. е. сделать так, чтобы test выше возвращало 1)? Тип Measure уже является экземпляром Monad с определенными bind и return. Есть ли способ по умолчанию определить put и get MonadState с точки зрения lift, bind и return, чтобы заставить его работать? Я старался:

get = lift   get
put = lift . put

но я не мог заставить типы (трансформер?) работать:

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

person cronburg    schedule 04.12.2014    source источник


Ответы (2)


Measure уже определено следующим образом:

newtype Measure a = Measure { unMeasure :: [Cond] -> Sampler (a, [Cond]) }

Вы можете видеть, что нет места для хранения вашего Int, поэтому вы не можете сделать его надлежащим экземпляром MonadState. Если вы хотите расширить Measure до MonadState, вы можете использовать монадный преобразователь StateT:

test :: StateT Int Measure Int
test = put 1 >> get >>= \i -> return i

Что здесь случилось? StateT s — это трансформер монад, который позволяет комбинировать монаду State s с любой другой монадой (в данном примере Measure)

person Michal Seweryn    schedule 04.12.2014
comment
Я думаю, мне нужен обратный порядок стека - что-то вроде test :: Measure (State Int ()), так как я хочу сделать sample :: Measure a -> [] -> IO [(a,P)] для возвращаемого значения test. Пробуем сейчас... Спасибо за быстрый ответ! - person cronburg; 04.12.2014
comment
@KarlC монада StateT внутренне выполняет обратный порядок; все преобразователи монад делают. Например, MaybeT определяется как: newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}, поэтому MaybeT IO () — это тип программы ввода-вывода, которая, если она завершится, будет содержать либо Nothing, либо Just (). Точно так же StateT определяется как newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}, поэтому, как только вы runStateT test startState у вас будет экземпляр Measure (Int, Int). - person CR Drost; 04.12.2014
comment
Теперь test :: StateT Int Measure Int помогает мне вместе с runStateT, чтобы получить Measure (Int,Int). Все еще пытаюсь понять, что характерно для примеров MaybeT и StateT из онлайн-вики Haskell, и что можно обобщить на другие монады... - person cronburg; 05.12.2014

Точный код, который в итоге сработал для меня:

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) []
person cronburg    schedule 04.12.2014