icz*_*icz 6 haskell existential-type gadt
我试图State在一个新类型中隐藏monad 的类型参数,但是我很难将存在的限定s与g要提供的一致evalFoo.我已经试过ExistentialQuantification,GADTs和RankNTypes,但有这些扩展是如何工作的一个公认非常缺乏了解.
惯用的Haskell如何实现这种外观?谢谢!
{-# 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
Run Code Online (Sandbox Code Playgroud)
目标是实现这样的目标,但能够提供以下任何实例RandomGen:
myRNG :: Foo Double
myRNG = Foo $ do
u <- state random
return u
Prelude> evalFoo myRNG (mkStdGen 123)
0.7804356004944119
Run Code Online (Sandbox Code Playgroud)
Foo构造函数类型中的存在量化意味着对于每个类型的值Foo,都有一些RandomGen用作其状态的实例.你想相反,虽然:你想给定任何值foo :: Foo,和任何情况下g的RandomGen,你可以使用g由封装在计算的状态foo.
所以让我们写一下:
{-# 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
Run Code Online (Sandbox Code Playgroud)
这可以按预期使用:
myRNG :: Foo Double
myRNG = MkFoo $ do
u <- state random
return u
Run Code Online (Sandbox Code Playgroud)
给
*Main> evalFoo myRNG (mkStdGen 123)
0.43927189736460226
Run Code Online (Sandbox Code Playgroud)
是的,不是0.78;)