且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

声明类型类的所有实例都在另一个类型类中,而不修改原始类声明

更新时间:2022-12-23 14:12:00

Crypto-API作者在这里。请不要这么做 - 这实际上违反了CryptoRandomGen的隐含属性。



也就是说,我会这样做:只要创建一个包装类型您的 RandomGen ,并使该新类型为 CryptoRandomGen 的实例。

  newtype AsCRG g = ACRG {unACRG :: g} 

实例RandomGen g => CryptoRandomGen(AsCRG g)其中
newGen = - 这是不可能实现的,只有一个'RandomGen'约束。也许你还想要一个'默认'的实例?
genSeedLength = - 这也不可能来自'RandomGen'
genBytes nr g =
let(g1,g2)= split g
randInts :: [Word32]
randInts = B.concat。 map Data.Serialize.encode
。 ((nr + 3)`div` 4)
$(randoms g1 :: [Word32])
in(B.nr randInts,g2)
reseed _ _ = - 不可能没有更多限制
newGenIO = - 不可能没有更多限制

所以你看,你可以拆分生成器(或管理许多中间生成器),使正确的数字 Int s(或者在我的情况下, Word32 s),对它们进行编码并返回字节。

因为 RandomGen 仅限于生成(和分割),所以没有任何直接的方法支持instatiation,reinstantiation或查询属性,如种子长度。

There is an Crypto.Random API inside the crypto-api package that specifies what it means for something to be a "pseudorandom number generator".

I have implemented this API using an instance of System.Random's RandomGen class, namely, StdGen:

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

However, this implementation is only for the StdGen type, but it would really work for anything in System.Random's RandomGen typeclass.

Is there a way to say that everything in RandomGen is a member of CryptoRandomGen using the given shim functions? I'd like to be able to do this in my own code, without having to change the source of either of those two libraries. My instincts would be to change the first line to something like

instance (RandomGen a) => CryptoRandomGen a where

but that doesn't appear to be syntactically correct.

Crypto-API author here. Please don't do this - it's really a violation of the implicit properties of CryptoRandomGen.

That said, here's how I'd do it: Just make a newtype that wraps your RandomGen and make that newtype an instance of 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

So you see, you can split the generator (or manage many intermediate generators), make the right number of Ints (or in my case, Word32s), encode them, and return the bytes.

Because RandomGen is limited to just generation (and splitting), there isn't any straight-forward way to support instatiation, reinstantiation, or querying properties such as the seed length.