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