5

I have a test function like below which uses runST to internally mutate state. I defined another function go within it which returns Int wrapped in ST as result (just playing with some ST concepts). The problem is that my type signature for the function seems to be wrong. If I comment out the function type signature, code runs fine. With type signature as in the commented code, it doesn't compile because the compiler interprets the state of the go function as different from the state in enclosing scope. I will appreciate pointers on how to define the function type signature to pass outer ST s to go function.

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

This is the compiler error I get if I uncomment type signature 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 }
4

2 回答 2

8

问题是当你说

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

s现在固定为任何s runST提供的东西——即我们不能将其视为类型变量,因为您的签名会让您相信[1]。当编译器说“刚性类型变量”时,这就是它的意思。为了强调它是固定的,让我们参考它作为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应该与any s一起工作,而不仅仅是S1,所以这是一个错误。gois的正确签名Int -> ST S1 Int,但当然我们只是S1为了论证的缘故而编造了,而 trueS1在源文件中没有名称,所以go即使它是正确的类型,也不能给它一个签名。

[1] 哦,你已经打开了,所以ScopedTypeVariables看起来. 这不起作用——作用域变量仅适用于带有. 您可以通过将签名移动到左侧来解决此问题:forallsforall<-

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

之后s将适当地确定范围。

于 2014-02-20T03:23:01.450 回答
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
于 2014-02-20T03:07:40.760 回答