[英]How to correctly qualify types for working with the (transformed) ST and random monads
Here is my code: 这是我的代码:
...
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
and here is the error message that I get: 这是我得到的错误消息:
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 () }
How do I fix this? 我该如何解决?
One way to fix it is to bring the type variables s
and g
into scope using the ScopedTypeVariables
extension, the other is to simply omit the local type signature on swap_op
. 修复它的一种方法是使用
ScopedTypeVariables
扩展将类型变量s
和g
放入范围,另一种方法是简单地省略swap_op
上的本地类型签名。
If the local signature is omitted, the type can be inferred -- that leaves, however, the problem of the constraint 如果省略了局部签名,则可以推断出类型 - 但是,这会留下约束的问题
MAI.MArray (STUArray s) GraphEdgeYaml (ST s)
that is needed. 这是必要的。 There are two options,
有两种选择,
STArray
STArray
STUArray
s indeed STUArray
If you change the array type to STArray
, no constraint is needed (since there is an instance MArray (STArray s) e (ST s)
that covers all element types), and without the local type signature it compiles without problems. 如果将数组类型更改为
STArray
,则不需要约束(因为存在覆盖所有元素类型的instance MArray (STArray s) e (ST s)
),并且没有本地类型签名,它编译时没有问题。
If you want to keep the STUArray
s, the function can only be used where an instance is in scope. 如果要保留
STUArray
,则只能在实例在范围内的情况下使用该函数。 It is best, usually, to provide such instances either where the class is defined (not an option here) or where the type is defined (that would be this module). 通常,最好在定义类的地方(这里不是选项)或定义类型的地方(将是此模块)提供此类实例。
So then you should write an 那么你应该写一个
instance MAI.MArray (STUArray s) GraphEdgeYaml (ST s)
in that module, with that instance, the constraint would be fulfilled and need not be placed on the function. 在该模块中,使用该实例,约束将被实现,并且不需要放在该函数上。 Note, however, that writing such an instance is not trivial.
但请注意,编写这样的实例并非易事。
Alternatively, you could add the constraint to the signature and load off the burden of defining an (orphan) instance to the user of swapLink
. 或者,您可以将约束添加到签名中,并减轻为
swapLink
用户定义(孤立)实例的swapLink
。
I don't know what a NodeName
is, but whether GraphEdgeYaml
is an unboxable type seems doubtful. 我不知道
NodeName
是什么,但是GraphEdgeYaml
是否是一个无法打包的类型似乎令人怀疑。 I would therefore recommend switching to STArray
s. 因此我建议切换到
STArray
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.