Hiding the state monad type parameter

I am trying to hide the State monad type parameter in the new type, but it is difficult for me to combine the existentially qualified s with g , which will be provided for evalFoo , I tried with ExistentialQuantification , GADTs and RankNTypes , but admittedly, I very poorly understood how these extensions work .

How would Haskell's idiomatic way of fulfilling this look? Thanks!

 {-# LANGUAGE GADTs #-} import Control.Monad.State import System.Random data Foo a where Foo :: RandomGen s => State sa -> Foo a evalFoo :: RandomGen g => Foo a -> g -> a evalFoo (Foo m) g = evalState mg 

The goal is to achieve something similar, but to provide any instance of RandomGen :

 myRNG :: Foo Double myRNG = Foo $ do u <- state random return u Prelude> evalFoo myRNG (mkStdGen 123) 0.7804356004944119 
+6
source share
2 answers

Existential quantification in the constructor type Foo means that for each value of type Foo there is some instance of RandomGen , which it uses as its state. You want the other way around: you want for any value of foo :: Foo and any instance of g for RandomGen you can use g as the state of a calculation encapsulated with Foo .

So write that instead:

 {-# LANGUAGE Rank2Types #-} import Control.Monad.State import System.Random newtype Foo a = MkFoo{ unFoo :: forall g. (RandomGen g) => State ga } 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 

gives

 *Main> evalFoo myRNG (mkStdGen 123) 0.43927189736460226 

Yes, not quite 0.78;)

+6
source

The problem is what you are describing. You cannot combine an existentially wrapped random seed with your initial random seed. The most obvious approach is to abandon existential quantification altogether and simply use this:

 runRandomly :: RandomGen g => State ga -> g -> a runRandomly (Foo m) g = evalState mg 

I do not see any problems with the most obvious approach in this context. If you really want to hide the type of seeds from the transformer, the answer of the cactus shows how to do it correctly.

In some other contexts, some similar existential wrappers can work by completing the seed with a transformer:

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

You can see an example of something similar in the foldl package.

+4
source

All Articles