Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hiding a State monad's s type parameter

I'm trying to hide the type parameter of a State monad in a new type, but I'm having a hard time unifying the existentially qualified s with the g to be provided for evalFoo. I've tried with ExistentialQuantification, GADTs, and RankNTypes, but have an admittedly very poor understanding of how these extensions work.

How would the idiomatic Haskell way to accomplish this look? Thanks!

{-# LANGUAGE GADTs #-}

import Control.Monad.State
import System.Random

data Foo a where
  Foo :: RandomGen s => State s a -> Foo a

evalFoo :: RandomGen g => Foo a -> g -> a
evalFoo (Foo m) g = evalState m g

The goal is to achieve something like this, but to able to supply any instance of RandomGen:

myRNG :: Foo Double
myRNG = Foo $ do
  u <- state random
  return u

Prelude> evalFoo myRNG (mkStdGen 123)
0.7804356004944119
like image 294
icz Avatar asked Dec 17 '15 05:12

icz


1 Answers

Existential quantification in the type of the Foo constructor would mean that for every value of type Foo, there is some instance of RandomGen that it uses as its state. You want the opposite, though: you want that given any value foo :: Foo, and any instance g of RandomGen, you can use g as the state of the computation encapsulated by foo.

So let's write that instead:

{-# LANGUAGE Rank2Types #-}

import Control.Monad.State
import System.Random

newtype Foo a = MkFoo{ unFoo :: forall g. (RandomGen g) => State g a }

evalFoo :: RandomGen g => Foo a -> g -> a
evalFoo = evalState . unFoo

This can be used as expected:

myRNG :: Foo Double
myRNG = MkFoo $ do
    u <- state random
    return u

giving

*Main> evalFoo myRNG (mkStdGen 123)
0.43927189736460226

Yeah, not quite 0.78 ;)

like image 55
Cactus Avatar answered Oct 17 '22 14:10

Cactus