tdammers / ginger

A Haskell implementation of the Jinja template language.
MIT License
77 stars 13 forks source link

Add support for records as GVal #57

Open flip111 opened 4 years ago

flip111 commented 4 years ago

Would it be possible to add support for records that become GVal dictionaries? Maybe with GHC.Generics instances can automatically be derived. I would prefer to just put my records straight into the template instead of writing conversion functions from record to hashmap.

tdammers commented 4 years ago

In principle, yes, of course. Automatically doing it for any record type would be a bad idea though, because a 1:1 mapping is often not what you want - not all records represent straightforward dumb data, after all, and it would only work for record types where all fields have GVal instances themselves.

Another thing worth thinking about is how names should work out; it is not clear at all whether the record field names should become Ginger dictionary keys directly, or if some name mangling should be applied. Haskell record fields often have prefixes due to the lack of per-record namespacing in the language, but on the Ginger side, we might not want to retain those prefixes. Haskell record fields generally use camel case, but we might prefer a different casing convention on the Ginger side. Those are all choices we should leave to the consumer.

All that said, I'm not at all opposed to the idea; if you want to sink some work into making it happen, I'm sure we can come up with something worth merging. Generics is probably the way to go here, or Template Haskell if we have to. I would only provide the tools though, not any actual instances, as that would (see above) be a bit too disruptive for my taste.

flip111 commented 4 years ago

I'm not so good yet with GHC.Generics .. this is as far as i get and it doesn't work

class GenericGVal rep where
  genericToGVal :: forall a. [(T.Text, a)]

instance GenericGVal f => GenericGVal (M1 D x f) where
  genericToGVal = genericToGVal @f

instance GenericGVal f => GenericGVal (M1 C x f) where
  genericToGVal = genericToGVal @f

instance Selector s => GenericGVal (M1 S s (K1 R t) f) where
  genericToGVal = [(T.pack $ selName (undefined :: M1 S s (K1 R t) ()), ????? )]

instance (GenericGVal a, GenericGVal b) => GenericGVal (a :*: b) where
  genericToGVal = genericToGVal @a <> genericToGVal @b

instance GenericGVal U1 where
  genericToGVal = []

I think all your objections:

Are the same problems that are being faced when mapping JSON to records. Aeson has a great solution for this where you can automatically derive the common case and implement the typeclass yourself (with some helpers) for the customizing. Take a look at this package for example https://hackage.haskell.org/package/aeson-casing

tdammers commented 4 years ago

Yep, aeson is pretty much what I had in mind. I'll take a closer look when I can make the time.

On Sat, Aug 29, 2020, 23:37 flip111 notifications@github.com wrote:

I'm not so good yet with GHC.Generics .. this is as far as i get and it doesn't work

class GenericGVal rep where genericToGVal :: forall a. [(T.Text, a)] instance GenericGVal f => GenericGVal (M1 D x f) where genericToGVal = genericToGVal @f instance GenericGVal f => GenericGVal (M1 C x f) where genericToGVal = genericToGVal @f instance Selector s => GenericGVal (M1 S s (K1 R t) f) where genericToGVal = [(T.pack $ selName (undefined :: M1 S s (K1 R t) ()), ????? )] instance (GenericGVal a, GenericGVal b) => GenericGVal (a :*: b) where genericToGVal = genericToGVal @a <> genericToGVal @b instance GenericGVal U1 where genericToGVal = []

I think all your objections:

  • customize mapping
  • naming of keys
  • casing

Are the same problems that are being faced when mapping JSON to records. Aeson has a great solution for this where you can automatically derive the common case and implement the typeclass yourself (with some helpers) for the customizing. Take a look at this package for example https://hackage.haskell.org/package/aeson-casing

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/tdammers/ginger/issues/57#issuecomment-683344581, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAK6HR5ZTHFCSRI6TQVWHB3SDFYINANCNFSM4QOLNHJA .