Closed lehins closed 7 months ago
That looks very nice!
It does seem to break deriving
on old LTS. But that looks fixable. Other than that, I don't see any downsides with this approach.
It may be worth circulating this on the libraries list: (1) this technique deserves to be more well-known, (2) perhaps the authors of PRNG implementations have feedback.
That's cute hack!
I don't think it's possible without dropping either type family or GHC<8.2. Prior to 8.2 GHC could derive newtype instances for classes with associated types. See https://gitlab.haskell.org/ghc/ghc/-/issues/2721
We can manually provide those instances, they don't have to be derived.
Nice :)
I figured how to improve it even further.
class RandomGen g where
type Splittable g :: Constraint
type Splittable g =
TypeError ('ShowType g ':<>: 'Text " is not a splittable RandomGen")
...
split :: Splittable g => g -> (g, g)
Any generator instance that is actually splittable only has to override the TypeError
with ()
:
instance RandomGen SM.SMGen where
type Splittable SM.SMGen = ()
...
split = SM.splitSMGen
Here what we get in ghci:
> data NoopGen = NoopGen
> :{
| instance RandomGen NoopGen where
| genWord64 _ = (0, NoopGen)
| split _ = error "Impossible"
| :}
> split NoopGen
<interactive>:8:1: error:
• NoopGen is not a splittable RandomGen
• In the expression: split NoopGen
In an equation for ‘it’: it = split NoopGen
CC @treeowl You've expressed interest in this in #97, what do you think about this approach?
Naturally, this is a backwards incompatible solution, but was always meant to be a breaking change. It can be included in random-1.3.0
whenever that might happen.
Closing in favor of #160
I think I figured out an elegant solution for differentiating splittable vs non-splittable PRNGs in a type safe way with very little breakage!!!
CC @idontgetoutmuch and @curiousleo We've discussed the problem here at some lengths: idontgetoutmuch/random#7
This is the change to the type class:
Which means only instances for PRNGs that are non splittable need to be adjusted, eg:
which if you try to use
split
function, will give you a nice error message:Instead of this ugly runtime error: