Declare all instances of a typeclass are in another typeclass without modifying the original class declarations

后端 未结 2 734
日久生厌
日久生厌 2021-01-23 08:39

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

2条回答
  •  一向
    一向 (楼主)
    2021-01-23 09:14

    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.

提交回复
热议问题