Lit*_*rum 1 haskell subclass instance typeclass
crypto-api包中有一个Crypto.Random API,用于指定"伪随机数生成器"的含义.
我使用System.Random的RandomGen类的实例,即StdGen实现了这个API:
instance CryptoRandomGen StdGen where
newGen bs = Right $ mkStdGen $ shift e1 24 + shift e2 16 + shift e3 8 + e4
where (e1 : e2 : e3 : e4 : _) = Prelude.map fromIntegral $ unpack bs
genSeedLength = Tagged 4
genBytes n g = Right $ genBytesHelper n empty g
where genBytesHelper 0 partial gen = (partial, gen)
genBytesHelper n partial gen = genBytesHelper (n-1) (partial `snoc` nextitem) newgen
where (nextitem, newgen) = randomR (0, 255) gen
reseed bs _ = newGen bs
Run Code Online (Sandbox Code Playgroud)
但是,此实现仅适用于StdGen类型,但它确实适用于System.Random的RandomGen类型类中的任何内容.
有没有办法说使用给定的填充函数,RandomGen中的所有内容都是CryptoRandomGen的成员?我希望能够在我自己的代码中执行此操作,而无需更改这两个库中的任何一个的源代码.我的直觉是将第一行改为类似的东西
instance (RandomGen a) => CryptoRandomGen a where
Run Code Online (Sandbox Code Playgroud)
但这似乎在语法上并不正确.
Crypto-API的作者在这里.请不要这样做 - 这实际上违反了CryptoRandomGen的隐式属性.
也就是说,我就是这样做的:只需创建一个包装你的新类型RandomGen,并将该newtype作为一个实例CryptoRandomGen.
newtype AsCRG g = ACRG { unACRG :: g}
instance RandomGen g => CryptoRandomGen (AsCRG g) where
newGen = -- This is not possible to implement with only a 'RandomGen' constraint. Perhaps you want a 'Default' instance too?
genSeedLength = -- This is also not possible from just 'RandomGen'
genBytes nr g =
let (g1,g2) = split g
randInts :: [Word32]
randInts = B.concat . map Data.Serialize.encode
. take ((nr + 3) `div` 4)
$ (randoms g1 :: [Word32])
in (B.take nr randInts, g2)
reseed _ _ = -- not possible w/o more constraints
newGenIO = -- not possible w/o more constraints
Run Code Online (Sandbox Code Playgroud)
所以你看,你可以分割生成器(或管理许多中间生成器),生成正确数量的Ints(或者在我的情况下,Word32s),编码它们,并返回字节.
因为RandomGen仅限于生成(和拆分),所以没有任何直接的方法来支持实例化,重新实例化或查询诸如种子长度之类的属性.