Lysxia / generic-data

Generic data types in Haskell, utilities for GHC.Generics
https://hackage.haskell.org/package/generic-data
MIT License
44 stars 9 forks source link

Modify fields by name #49

Closed Lysxia closed 2 years ago

Lysxia commented 3 years ago

Do this: https://gist.github.com/sjoerdvisscher/480ea5755477b5da580ca3708991fb05

dwincort commented 2 years ago

I implemented something similar because I needed it myself. This is what I came up with:

data OnField (s :: Symbol) (f :: Type -> Type) :: Type
type instance GSurgery (OnField x f) g = GOnField x f g

type family GOnField (x :: Symbol) (f :: Type -> Type) (g :: k -> Type) :: k -> Type where
  GOnField x f (M1 S ('MetaSel ('Just x) a b c) r) = M1 S ('MetaSel ('Just x) a b c) (GOnField x f r)
  GOnField x f (M1 C m r) = M1 C m (GOnField x f r)
  GOnField x f (M1 D m r) = M1 D m (GOnField x f r)
  GOnField x f (M1 s m r) = M1 s m r
  GOnField x f (r :+: s) = GOnField x f r :+: GOnField x f s
  GOnField x f (r :*: s) = GOnField x f r :*: GOnField x f s
  GOnField x f (K1 i a) = K1 i (f a)
  GOnField x f U1 = U1
  GOnField x f V1 = V1

It's used just like OnFields, but you write OnField "foo" Sum or similar. It's not quite as general as your OverrideFields, but it is quite simple. I can PR if you like, or you can just copy the code from here if you like it.

Lysxia commented 2 years ago

Thanks, that looks good! I can do it when I get around to it soon. The one change I will add is to defunctionalize the K1 i (f a) case so the resulting field can be something other than a type application. (EDIT: changed my mind, cf. #50 )