2015-12-07 3 views
0

В следующем примере:Использования runRVar в течение некоторого стека монады трансформатора

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 

Я запутался:

  1. почему подпись обув вынуждена быть StateT Int RVar() даже если toss' имеет подпись m Bool для некоторых MonadRandom m

  2. Почему testFoo должен быть запущен с некоторыми StdRandom, хотя toss' уже runRVar с StdRandom. Это имеет смысл с точки зрения типа, но в котором используется StdRandom? Если этот вопрос имеет смысл вообще.

  3. Можно ли переписать подпись foo «s, как MonadRandom m => StateT Int m()

+0

Тип 'runRVar' очень общий - в этом случае первый' runRVar' создается при типе 'RVar Bool -> StdRandom -> RVar Bool', когда вы используете' toss ' 'внутри' foo' и 'bar'. И эта функция - это только тождество (или должно быть). В любом случае StdRandom ничего не делает - когда вы пишете 'runRVar ... StdRandom', это просто означает использование интерфейса MonadRandom в качестве источника случайности. – user2407038

ответ

4
  1. Когда ограничение -мономорфизма на (это по умолчанию), все виды вяжущих верхнего уровня будут выведены мономорфные.
  2. Вы должны добавить RVar в стек монады, как вы делали в bar. MonadRandom слишком общий. StdRandom - это просто конструктор данных, поэтому он не имеет определенного состояния. random-fu должен автоматически обновлять состояние.
  3. Просто добавьте подпись. См. 1.
+0

Прошу прощения, просто уточните, вы говорите, установив «NoMonomorphismRestriction», теперь я вижу, что я могу написать «bar :: MonadRandom m => StateT Int m()'. * Однако * я должен написать 'StateT Int RVar()' потому что 'MonadRandom m' слишком общий? И вы говорите, что «StdRandom» - это что-то, что удовлетворяет методу typechecker и фактически не инициализирует случайное семя правильно? – chibro2

+1

Да, в значительной степени. При написании RVar вам не нужно делать runRVar * внутри * StateT и может просто предоставить случайный генератор извне один раз. Это также облегчает изменение используемого генератора случайных чисел (вам просто нужно передать/отредактировать его один раз вместо замены всех вхождений StdRandom). –