Imperative port of haskell optics stated simply

monkyyy crazymonkyyy at gmail.com
Wed Jul 8 01:37:59 UTC 2026


Haskell as always got an idea first by mashing some keys together 
and a surprisingly something compiled then it takes decades to 
untangle it. See monads.

Math NERDS, then spend 100000s of big math words and arcane 
symbols intentionally hiding the result. See monads.

This is my current understanding of the "optics" libs and how 
they could be metaprogrammed in d:

---

Optics in imperative languages are a kind of sumtypes built as 
wrappers around `void*` that contain a metaprogram on assignment. 
Note, everything here is a reference type and therefore can dodge 
complexity of handling the expression problem and determining 
`.sizeof`. If you wanted a `sumtype!(vec!2,vec!3...vec!99)` thru 
no fault of the author given the design goals, you would need to 
initialize 100 templates preemptively even if you never used 
them, you would need to gather them all into one place, and you 
would be picking an upper bound on your vec family. `void*` does 
not need to know `.sizeof` and so you can make tradeoffs of 
knowing where the data is with the openness of your sumtype.

`Lens!(vec!2,vec!3)` handles the overlap of the `fields` shared 
by the types it is initialized with i.e. `x,y` and maybe can make 
a `nullable!z`; this makes an opDispatch!"x" a trivial mixin of a 
cast and you get a ref of a `vec!?.x`. On opAssign you check that 
any assignments match the generated schema, this allows you to 
assign vec!99 in a separate compilation or after the lens was 
initialized. Implicitly vec!1 would fail the assignment at 
compile time.

`Prism!(float)` grabs a bit of data on opAssign to produce a 
range, a vec!99 should be range of 99 floats, this may discard 
other fields and its probably not that efficient as its going to 
be a slice of offsets. You may also want to grab a specific field 
such as `Prism!(float,"z")`.

`Iso` is a 0th special case of a lens, you dont feed it `vec!2`, 
instead it captures some metadata, such as `dim` from the family 
of vec's or typeinfo

These types should compose `Lens!(vec!3)` should be assignable to 
`Lens!(vec!2). Prisms should "add" together, allowing for the one 
pointer to see many ranges.

An `Affine` should be a combination of a `Len-y` and a `Prism-y` 
optic, consider 
`Affine!(Lens!(vec!2),Prism!(float,"radius"),Prism!(float,"size"))` and `square` and a `circle`, using the `Lens` you should be able to move the shape around, with the prisms you should be able to do some kind of pattern matching on the remaining fields


More information about the Digitalmars-d mailing list