Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use GHC.Generics to restrict generic function domain

Say I have a typeclass:

data Proxy a = Proxy
class Fixed a where 
  fixed :: Proxy a -> Int

The definition for fixed is quite trivial so I derive it using GHC.Generics:

class GFixed f where 
  gfixed :: Proxy (f a) -> Int

instance (GFixed f, GFixed g) => GFixed (f :*: g) where ...

instance (GFixed f, GFixed g) => GFixed (f :+: g) where ...

instance GFixed f => GFixed (M1 i c f) where ...

instance Fixed a => GFixed (K1 i a) where ...

....

default fixed :: (Generic a, GFixed (Rep a)) => Proxy a -> Int
fixed _ = fixed (Proxy :: Proxy (Rep a b))

I don't include an instance for GFixed U1 because it doesn't make sense to have an instance of Fixed for void types. My understanding of Generics machinery is not very good - specifically, what the types of M1 and K1 mean. The question is as follows: can I restrict GFixed at the type level, so that the default definition of fixed doesn't work with recursive types?

For example, if I write:

data Void
instance Fixed Void

I get a type error: No instance for (GFixed V1). I would like to get type error for things like instance Fixed [Int].

like image 292
user2407038 Avatar asked Nov 18 '25 20:11

user2407038


1 Answers

The documentation is moderately helpful for the meanings of the constructors. M1 specifies meta-information (such as the names of record selectors), and K1 is a bit of a grab-bag of various things with kind *. If you want to disallow all recursion, you'll need to ensure that no instance in scope matches K1 R a. You'll still want some of the other K instances in scope, so you should change

instance Fixed a => GFixed (K1 i a) where

to

instance Fixed a => GFixed (K1 P a) where

I don't know if there are other values that can be the first parameter to K1, but if any arise it should be safe to add them, except for K1 R of course.

like image 179
John L Avatar answered Nov 20 '25 19:11

John L



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!