TL;DR: given a functional-reference/optics library, should you be able to say "set the endpoint of this path to X, creating empty elements along the way as necessary"?
Scala and Elm have a lens implementation libraries (Scala, Elm). They add an Optional
to the canonical Lens/Prism/Iso types. It's useful for dictionaries/maps/hashes. I think it corresponds roughly to Haskell/Lens's Lens.At. I have a question about the behavior of Elm's version that seems Not What You'd Want, but can't interpret the Haskell or Scala versions well enough to determine an answer from them.
The issue is composing two Optional
values together. Suppose we have two Optional
s that focus on particular keys in a dictionary:
top
is an Optional that follows a"one"
key if it exists. (It returns eitherJust the-value-for-the-key
orNothing
.)bottom
is an Optional that follows a"two"
key if it exists.
Importantly, if you set a key that doesn't exist, both of them add it. Here's an example:
> import Monocle.Optional as Opt
> import Monocle.Common as Common
> top = Common.dict "one"
> top.set 3 Dict.empty
Dict.fromList [("one",3)] : Dict.Dict String number
However, consider the case if you compose the two Optional
s:
> bottom = Common.dict "two"
> composed = Opt.compose top bottom
As you'd expect, if you use the composed
Optional
on a structure whose "one"
key points to an empty Dict
, that dict gets updated:
> > composed.set "new!" (Dict.singleton "one" Dict.empty)
{"one" : {"two" : "new!"}}
(I used a literal map notation to make the result clearer.)
Great. But if I use that composed Optional
on a Dict
that's entirely empty, it just fails:
> composed.set "new!" Dict.empty
{}
I can see an argument that it should fail, rather than producing {"one" : {"two" : "new!"}}
. However, silently doing a different thing depending on whether it's a composed Optional
or not seems like asking for trouble.
I understand (I think) the motivation: I can't see a way to implement the behavior I'd want without creating an Optional
with a "create an empty structure" function. And I haven't worked through how that would affect composing with prisms or lenses.
I'm looking for people to say either "that behavior makes sense because " or "that's a (perhaps unavoidable) weakness of the Elm version (or all versions)."