* Focus

#+ATTR_HTML: :style margin-left: auto; margin-right: auto;

An experiment with functional optics[fn:1].

A lens is a value that composes a getter and a setter function to produce a bidirectional view into a data structure. This definition is intentionally broad—lenses are a very general concept, and they can be applied to almost any kind of value that encapsulates data.
  -- [[][Racket 'lens' documentation]] 

** Usage

To construct a lens:

#+BEGIN_SRC elixir
  # A lens for the key :name

  # A lens for the key "name"

  # A lens for the second item in a list/tuple:

Each lens provides both a getter and a setter for the accessor it was created for.

Lenses can be used to access and/or modify structured data:

#+BEGIN_SRC elixir
  # Extract a value from a simple map:

  person = %{name: "Homer"}
  nameLens = Focus.Lens.make_lens(:name)

  Focus.Lens.view!(nameLens, person) == "Homer"
  # true

  Focus.Lens.set(nameLens, person, "Bart")
  # %{name: "Bart"}

  Focus.Lens.over(nameLens, person, &String.upcase/1)
  # %{name: "HOMER"}

Their real utility comes in operating on nested data. Lenses can be created by composing other lenses in order to traverse a data structure:

#+BEGIN_SRC elixir
  person = %{
    name: "Homer",
    address: %{
      locale: %{
        number: 742,
        street: "Evergreen Terrace",
        city: "Springfield",
      state: "???"

  # To access the street, we can compose the lenses that lead there from the top level.
  # Lenses can be composed with Focus.Lens.compose/2, or the infix (~>) operator.

  address = Focus.Lens.make_lens(:address)
  locale =  Focus.Lens.make_lens(:locale)
  street =  Focus.Lens.make_lens(:street)

  ~> locale
  ~> street
  |> Focus.Lens.view!(person)
  # "Evergreen Terrace"

  ~> locale
  ~> street
  |> Focus.Lens.set(person, "Fake Street")
  # person = %{
  #   name: "Homer",
  #   address: %{
  #     locale: %{
  #       number: 742,
  #       street: "Fake Street",
  #       city: "Springfield",
  #     },
  #     state: "???"
  #   }
  # }

** Functions 
*** Lens creation
  + =Focus.Lens.make_lens/1=

*** Lens application
  + =Focus.Lens.view!/2=
  + =Focus.Lens.view/2=
  + =Focus.Lens.set/3=
  + =Focus.Lens.over/3=
  + =Focus.Lens.apply_list/2=

*** Lens composition
  + =Focus.Lens.compose/2, (~>)=
  + =Focus.Lens.alongside/2=
** Installation

  1. Add =focus= to your list of dependencies in =mix.exs=:

    #+BEGIN_SRC elixir
      def deps do
        [{:focus, "~> 0.1.0"}]

  2. Ensure =focus= is started before your application:

    #+BEGIN_SRC elixir
      def application do
        [applications: [:focus]]

** References
+ [[][A Little Lens Starter Tutorial]]
+ [[][Lenses in Functional Programming]]
+ [[][Control.Lens Tutorial]]

* Footnotes

[fn:1] This library currently combines Lenses, Prisms, and Traversals in its implementation of Lens.