声明一个类型类的所有实例都在另一个类型类中,而不修改原始类声明
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
但是,此实现仅适用于 StdGen 类型,但它确实适用于 System.Random 的 RandomGen 类型类中的任何内容。
有没有办法说 RandomGen 中的所有内容都是使用给定 shim 函数的 CryptoRandomGen 的成员?我希望能够在自己的代码中执行此操作,而不必更改这两个库中任何一个的源。我的直觉是将第一行更改为类似的内容
instance (RandomGen a) => CryptoRandomGen a where
,但这在语法上似乎不正确。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Crypto-API 作者在这里。请不要这样做 - 这确实违反了 CryptoRandomGen 的隐式属性。
也就是说,我会这样做:只需创建一个包装
RandomGen
的新类型,并使该新类型成为CryptoRandomGen
的实例。所以你看,你可以分割生成器(或管理许多中间生成器),制作正确数量的
Int
(或者在我的例子中,Word32
),对它们进行编码,并返回字节。由于 RandomGen 仅限于生成(和分割),因此没有任何直接的方法来支持实例化、重新实例化或查询种子长度等属性。
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 ofCryptoRandomGen
.So you see, you can split the generator (or manage many intermediate generators), make the right number of
Int
s (or in my case,Word32
s), 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.据我所知,这是不可能的,除非您愿意打开
UndecidableInstances
(当然,这可以使类型检查器进入无限循环)。下面是一个示例,它使Monad
的每个实例都成为Functor
的实例:测试:
在您的情况下,这转化为:
顺便说一句,我曾经问过如何在不使用haskell-cafe 上的
UndecidableInstances
并得到 这个答案(与托马斯提出的解决方法相同;我认为丑陋的)。As far as I know, this is impossible, unless you're willing to turn on
UndecidableInstances
(which, of course, can make the typechecker go in an infinite loop). Here's an example that makes every instance ofMonad
an instance ofFunctor
:Testing:
In your case, this translates to:
As an aside, I once asked how to implement this without
UndecidableInstances
on haskell-cafe and got this answer (the same workaround that Thomas proposed; I consider it ugly).