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
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 ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With