我试图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
目标是实现这样的目标,但能够提供以下任何实例RandomGen
:
myRNG :: Foo Double myRNG = Foo $ do u <- state random return u Prelude> evalFoo myRNG (mkStdGen 123) 0.7804356004944119
Cactus.. 6
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
这可以按预期使用:
myRNG :: Foo Double myRNG = MkFoo $ do u <- state random return u
给
*Main> evalFoo myRNG (mkStdGen 123) 0.43927189736460226
是的,不是0.78;)
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
这可以按预期使用:
myRNG :: Foo Double myRNG = MkFoo $ do u <- state random return u
给
*Main> evalFoo myRNG (mkStdGen 123) 0.43927189736460226
是的,不是0.78;)