在runST函数中传递范围状态

时间:2014-02-20 00:44:09

标签: haskell st

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

{-# 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

如果我取消注释类型签名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 }

2 个答案:

答案 0 :(得分:7)

麻烦的是,当你说

gen <- ... :: (forall s. ST s (Gen (PrimState (ST s))))

s现在已修复s runST提供的任何内容 - 即我们无法将其视为类型变量,因为您的签名会让您相信[1] ]。当编译器说&#34;刚性类型变量&#34;时,这就是它的含义。为了强调它是固定的,让我们将其称为S1以获得此答案。

请注意

let go :: Int -> ST s Int

相当于

let go :: forall s. Int -> ST s Int

即,go必须适用于任何 s。但是你说了

v <- uniformR (1,x) gen

尝试绑定类型ST S1 <something>的计算。 go应该与任何 s一起使用,而不仅仅是S1,所以这是一个错误。 go的正确签名是Int -> ST S1 Int,但我们当然只是为了论证而编造S1,并且真正的S1在源代码中没有名称文件,因此go无法给出签名,即使它的类型很好。

[1]哦,你已经ScopedTypeVariables了,所以看起来forall就在那里,因为你正在尝试范围s。这不起作用 - 范围变量仅适用于forall的函数体。您可以通过将签名移到<-

的左侧来解决此问题
(gen :: Gen (PrimState (ST s))) <- initialize ...

之后s将被正确确定范围。

答案 1 :(得分:1)

不是一个完整的答案,但我可以通过传递gen

来使事情有效
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 go3 ::  (Num b, Variate b) => Gen (PrimState (ST s)) -> b -> ST s b
         go3 g x' = uniformR (1,x') g
     go3 gen 100