声明类型类的所有实例都在另一个类型类中,而不修改原始类声明 [英] Declare all instances of a typeclass are in another typeclass without modifying the original class declarations

查看:104
本文介绍了声明类型类的所有实例都在另一个类型类中,而不修改原始类声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

crypto-api包内有一个Crypto.Random API,它指定某物为伪随机数生成器的含义。

我已经实现了此API使用System.Random的RandomGen类的一个实例,即StdGen:

 实例CryptoRandomGen StdGen其中
newGen bs = Right $ mkStdGen $ shift e1 24 + shift e2 16 + shift e3 8 + e4
其中(e1:e2:e3:e4:_)= Prelude.map fromIntegral $ unpack bs
genSeedLength = Tagged 4
genBytes ng = Right $ genBytesHelper n空g
其中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

然而,这个实现只适用于StdGen类型,但它对于System.Random的RandomGen类型lass。

有没有办法说RandomGen中的所有内容都是使用给定的匀场函数的CryptoRandomGen的成员?我希望能够在我自己的代码中做到这一点,而不必更改这两个库中的任何一个的源代码。我的直觉是将第一行改成类似于

 实例(RandomGen a)=> CryptoRandomGen a,其中

但看起来在语法上不正确。

解决方案

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.

这篇关于声明类型类的所有实例都在另一个类型类中,而不修改原始类声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆