Skip to content

Instantly share code, notes, and snippets.

@marick
Last active October 3, 2017 22:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marick/76e40479b9f5a1fc63e560c33351f884 to your computer and use it in GitHub Desktop.
Save marick/76e40479b9f5a1fc63e560c33351f884 to your computer and use it in GitHub Desktop.

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 Optionals that focus on particular keys in a dictionary:

  • top is an Optional that follows a "one" key if it exists. (It returns either Just the-value-for-the-key or Nothing.)
  • 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 Optionals:

> 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)."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment