在runST函数中传递范围状态

Sal*_*Sal 5 haskell st

我有一个像下面的测试函数,用于runST内部变异状态.我go在其中定义了另一个函数,它返回Int包含在ST结果中(只是玩一些ST概念).问题是我的函数类型签名似乎是错误的.如果我注释掉函数类型签名,代码运行正常.使用注释代码中的类型签名,它不会编译,因为编译器将go函数的状态解释为与封闭范围中的状态不同.我将理解如何定义函数类型签名以将外部函数传递ST sgo函数的指针.

{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Data.Word(Word32)
import Data.Vector.Unboxed as U hiding (mapM_,create)
import Control.Monad.ST as ST
import Control.Monad.Primitive (PrimState)
import System.Random.MWC

test :: Word32 -> Int
test x = runST $ do
     gen <- initialize (U.singleton $ fromIntegral x :: U.Vector Word32) :: (forall s. ST s (Gen (PrimState (ST s))))
     let --go :: Int -> ST s Int
         go x = do
            v <- uniformR (1,x) gen
            return v
     i <- go 100
     return i
Run Code Online (Sandbox Code Playgroud)

如果我取消注释类型签名,这是我得到的编译器错误go :: Int -> ST s Int:

Couldn't match type `s1' with `s'
  `s1' is a rigid type variable bound by
       the type signature for go :: Int -> ST s1 Int at A.hs:12:16
  `s' is a rigid type variable bound by
      a type expected by the context: ST s Int at A.hs:10:10
Expected type: Gen (PrimState (ST s1))
  Actual type: Gen s
In the second argument of `uniformR', namely `gen'
In a stmt of a 'do' block: v <- uniformR (1, x) gen
In the expression:
  do { v <- uniformR (1, x) gen;
       return v }
Run Code Online (Sandbox Code Playgroud)

luq*_*qui 7

麻烦的是,当你说

gen <- ... :: (forall s. ST s (Gen (PrimState (ST s))))
Run Code Online (Sandbox Code Playgroud)

s现在固定为任何s runST提供 - 即我们不能认为它是一个类型变量,因为你的签名会让你相信[1].当编译器说"刚性类型变量"时,这意味着它.为了强调它是固定的,让我们参考它作为S1这个答案.

请注意

let go :: Int -> ST s Int
Run Code Online (Sandbox Code Playgroud)

相当于

let go :: forall s. Int -> ST s Int
Run Code Online (Sandbox Code Playgroud)

即,go必须为任何 工作s.但是你说

v <- uniformR (1,x) gen
Run Code Online (Sandbox Code Playgroud)

它试图绑定类型的计算ST S1 <something>. go应该与任何人合作 s,而不仅仅是S1,所以这是一个错误.正确的签名goInt -> ST S1 Int,但当然我们只是S1为了论证而弥补,并且true S1在源文件中没有名称,因此go即使它是良好类型的,也不能给出签名.

[1]哦,你已经ScopedTypeVariables开始了,所以看起来就像forall是在那里,因为你正试图扩大范围s.这不起作用 - 范围变量仅适用于函数体forall.您可以通过将签名移动到以下的左侧来解决此问题<-:

(gen :: Gen (PrimState (ST s))) <- initialize ...
Run Code Online (Sandbox Code Playgroud)

之后s将适当确定范围.