[英]How to correctly qualify types for working with the (transformed) ST and random monads
这是我的代码:
...
import System.Random ( RandomGen, next, split )
import qualified Data.Array.MArray as MAI
import Data.Array.ST.Safe( STUArray )
import Control.Monad.ST.Safe(ST)
import qualified Control.Monad.Random as CMR
import Control.Monad.Trans.Class( lift )
data GraphEdgeYaml = GraphEdgeYaml {
specie1:: NodeName,
specie2 :: NodeName,
sign :: Int,
speed :: Int
}
type LinksSTA s = STUArray s Int GraphEdgeYaml
-- Change a simple link
swapLink :: RandomGen g =>
LinksSTA s
-> g
-> ST s g
swapLink graph generator =
let
swap_op :: CMR.RandT g (ST s) ()
swap_op = do
(low_limit, high_limit) <- lift $ MAI.getBounds graph
idx_value <- CMR.getRandomR (low_limit, high_limit)
return ()
in do
(_, new_generator) <- CMR.runRandT swap_op generator
return new_generator
这是我得到的错误消息:
hs/SignMatrixBuild/Randomize.hs:43:26:
Could not deduce (RandomGen g1)
arising from a use of `CMR.getRandomR'
from the context (RandomGen g)
bound by the type signature for
swapLink :: RandomGen g => LinksSTA s -> g -> ST s g
at hs/SignMatrixBuild/Randomize.hs:(38,1)-(47,28)
Possible fix:
add (RandomGen g1) to the context of
the type signature for swap_op :: CMR.RandT g1 (ST s1) ()
or the type signature for
swapLink :: RandomGen g => LinksSTA s -> g -> ST s g
In a stmt of a 'do' block:
idx_value <- CMR.getRandomR (low_limit, high_limit)
In the expression:
do { (low_limit, high_limit) <- lift $ MAI.getBounds graph;
idx_value <- CMR.getRandomR (low_limit, high_limit);
return () }
In an equation for `swap_op':
swap_op
= do { (low_limit, high_limit) <- lift $ MAI.getBounds graph;
idx_value <- CMR.getRandomR (low_limit, high_limit);
return () }
我该如何解决?
修复它的一种方法是使用ScopedTypeVariables
扩展将类型变量s
和g
放入范围,另一种方法是简单地省略swap_op
上的本地类型签名。
如果省略了局部签名,则可以推断出类型 - 但是,这会留下约束的问题
MAI.MArray (STUArray s) GraphEdgeYaml (ST s)
这是必要的。 有两种选择,
STArray
STUArray
如果将数组类型更改为STArray
,则不需要约束(因为存在覆盖所有元素类型的instance MArray (STArray s) e (ST s)
),并且没有本地类型签名,它编译时没有问题。
如果要保留STUArray
,则只能在实例在范围内的情况下使用该函数。 通常,最好在定义类的地方(这里不是选项)或定义类型的地方(将是此模块)提供此类实例。
那么你应该写一个
instance MAI.MArray (STUArray s) GraphEdgeYaml (ST s)
在该模块中,使用该实例,约束将被实现,并且不需要放在该函数上。 但请注意,编写这样的实例并非易事。
或者,您可以将约束添加到签名中,并减轻为swapLink
用户定义(孤立)实例的swapLink
。
我不知道NodeName
是什么,但是GraphEdgeYaml
是否是一个无法打包的类型似乎令人怀疑。 因此我建议切换到STArray
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.