[英]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.