{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreigz5mwu4xe5i43s6b7jft55pasjbdd333y3kujue6s3lz3sevy2ve",
    "uri": "at://did:plc:pi6woz4d47bkuws673w2il2r/app.bsky.feed.post/3mmm73wzcvf72"
  },
  "path": "/t/how-do-i-implement-this-transformation-using-generics/14153#post_2",
  "publishedAt": "2026-05-24T14:29:04.000Z",
  "site": "https://discourse.haskell.org",
  "tags": [
    "@d"
  ],
  "textContent": "It’s not often someone asks about generics and means `Data.Data`!\n\nHere’s one way to do it, setting the `c` type of `gfoldl` to `(->) Int`. `fld` is the function that handles one field of a constructor. Within `fld`, the `k j d` calls mean: continue with the rest of the fields (to the left) of this constructor, using `j` as increment value and `d` as the replacement value for the current field. So in the case of an `Int` field, we use `d + j` as replacement, in the case of `DeeperList`, we recurse (using `go`) with `j + 1` as increment. Otherwise (here only in the case of `List`) recurse with the current increment value.\n\nPattern matching on `Refl` tells the compiler that the two arguments to `eqT` are equal, which we need in the `Int` case, otherwise `d + j` wouldn’t type-check.\n\n\n    incr :: Int -> List -> List\n    incr = go\n      where\n        go :: Data d => Int -> d -> d\n        go i l = gfoldl fld const l i\n        fld :: forall d b. Data d => (Int -> d -> b) -> d -> Int -> b\n        fld k d j = case eqT @d @Int of\n          Just Refl -> k j (d + j)\n          Nothing -> case eqT @d @DeeperList of\n            Just Refl -> k j (go (j + 1) d)\n            Nothing -> k j (go j d)\n",
  "title": "How do I implement this transformation using generics?"
}