Focus (focus v0.4.0)

Common functions usable by lenses, prisms, and traversals.

Link to this section Summary

Functions

Infix lens composition

Compose a pair of lenses to operate at the same level as one another. Calling Focus.view/2, Focus.over/3, or Focus.set/3 on an alongside composed pair returns a two-element tuple of the result.

Compose with most general lens on the left

Partially apply a lens to Focus.over/3, fixing the lens argument and returning a function that takes a Types.traversable and an update function.

Partially apply a lens to Focus.set/3, fixing the optic argument and returning a function that takes a Types.traversable and a new value.

Fix Focus.view/2 on a given optic. This partially applies Focus.view/2 with the given optic and returns a function that takes a Types.traversable structure.

Check whether an optic's target is present in a data structure.

Check whether an optic's target is not present in a data structure.

Wrapper around Focusable.over/3

Wrapper around Focusable.set/3

Wrapper around Focusable.view/2

Given a list of lenses and a structure, apply Focus.view/2 for each lens to the structure.

Link to this section Functions

Specs

Infix lens composition

Examples

iex> import Focus
iex> marge = %{name: "Marge", address: %{
...>   local: %{number: 123, street: "Fake St."},
...>   city: "Springfield"}
...> }
iex> address_lens = Lens.make_lens(:address)
iex> local_lens = Lens.make_lens(:local)
iex> street_lens = Lens.make_lens(:street)
iex> address_lens ~> local_lens ~> street_lens |> Focus.view(marge)
"Fake St."
Link to this function

alongside(map1, map2)

Specs

Compose a pair of lenses to operate at the same level as one another. Calling Focus.view/2, Focus.over/3, or Focus.set/3 on an alongside composed pair returns a two-element tuple of the result.

Examples

iex> nums = [1,2,3,4,5,6]
iex> Focus.alongside(Lens.idx(0), Lens.idx(3))
...> |> Focus.view(nums)
{1, 4}

iex> bart = %{name: "Bart", parents: {"Homer", "Marge"}, age: 10}
iex> Focus.alongside(Lens.make_lens(:name), Lens.make_lens(:age))
...> |> Focus.view(bart)
{"Bart", 10}
Link to this function

compose(map1, map2)

Specs

Compose with most general lens on the left

Examples

iex> marge = %{
...>   name: "Marge",
...>   address: %{
...>     street: "123 Fake St.",
...>     city: "Springfield"
...>   }
...> }
iex> address_lens = Lens.make_lens(:address)
iex> street_lens = Lens.make_lens(:street)
iex> composed = Focus.compose(address_lens, street_lens)
iex> Focus.view(composed, marge)
"123 Fake St."
Link to this function

fix_over(lens, f \\ fn x -> x end)

Specs

Partially apply a lens to Focus.over/3, fixing the lens argument and returning a function that takes a Types.traversable and an update function.

Examples

iex> upcase_name = Lens.make_lens(:name)
...> |> Focus.fix_over(&String.upcase/1)
iex> %{name: "Bart", parents: {"Homer", "Marge"}}
...> |> upcase_name.()
%{name: "BART", parents: {"Homer", "Marge"}}

iex> fst = Lens.idx(0)
iex> states = [:maryland, :texas, :illinois]
iex> Focus.over(fst, states, &String.upcase(Atom.to_string(&1)))
["MARYLAND", :texas, :illinois]

Specs

Partially apply a lens to Focus.set/3, fixing the optic argument and returning a function that takes a Types.traversable and a new value.

Examples

iex> name_setter = Lens.make_lens(:name)
...> |> Focus.fix_set
iex> %{name: "Bart", parents: {"Homer", "Marge"}}
...> |> name_setter.("Lisa")
%{name: "Lisa", parents: {"Homer", "Marge"}}

iex> fst = Lens.idx(0)
iex> states = [:maryland, :texas, :illinois]
iex> Focus.over(fst, states, &String.upcase(Atom.to_string(&1)))
["MARYLAND", :texas, :illinois]
Link to this function

fix_view(optic)

Specs

Fix Focus.view/2 on a given optic. This partially applies Focus.view/2 with the given optic and returns a function that takes a Types.traversable structure.

Examples

iex> view_name = Lens.make_lens(:name)
...> |> Focus.fix_view
iex> homer = %{name: "Homer"}
iex> view_name.(homer)
"Homer"
iex> [homer, %{name: "Marge"}, %{name: "Bart"}]
...> |> Enum.map(&view_name.(&1))
["Homer", "Marge", "Bart"]
Link to this function

has(optic, structure)

Specs

Check whether an optic's target is present in a data structure.

Examples

iex> first_elem = Lens.idx(1)
iex> first_elem |> Focus.has([0])
false

iex> name = Lens.make_lens(:name)
iex> name |> Focus.has(%{name: "Homer"})
true
Link to this function

hasnt(optic, structure)

Specs

Check whether an optic's target is not present in a data structure.

Examples

iex> first_elem = Lens.idx(1)
iex> first_elem |> Focus.hasnt([0])
true

iex> name = Lens.make_lens(:name)
iex> name |> Focus.hasnt(%{name: "Homer"})
false
Link to this function

over(optic, structure, f)

Specs

Wrapper around Focusable.over/3

Arguments can be passed in with either the lens first and data structure second or vice versa. Passing the data structure first allows Focus.over/3 to fit neatly in pipeline operations.

Examples

iex> marge = %{
...>   name: "Marge",
...>   address: %{
...>     street: "123 Fake St.",
...>     city: "Springfield"
...>   }
...> }
iex> name_lens = Lens.make_lens(:name)
iex> name_lens
...> |> Focus.over(marge, &String.upcase/1)
%{
  name: "MARGE",
  address: %{
    street: "123 Fake St.",
    city: "Springfield"
  }
}
iex> marge
...> |> Focus.over(name_lens, &String.upcase/1)
%{
  name: "MARGE",
  address: %{
    street: "123 Fake St.",
    city: "Springfield"
  }
}
Link to this function

set(optic, structure, v)

Specs

Wrapper around Focusable.set/3

Arguments can be passed in with either the lens first and data structure second or vice versa. Passing the data structure first allows Focus.set/3 to fit neatly in pipeline operations.

Examples

iex> marge = %{ ...> name: "Marge", ...> address: %{ ...> street: "123 Fake St.", ...> city: "Springfield" ...> } ...> } iex> name_lens = Lens.make_lens(:name) iex> name_lens ...> |> Focus.set(marge, "Marjorie") %{ name: "Marjorie", address: %{

street: "123 Fake St.",
city: "Springfield"

} } iex> marge ...> |> Focus.set(name_lens, "Marjorie") %{ name: "Marjorie", address: %{

street: "123 Fake St.",
city: "Springfield"

} }

Link to this function

view(optic, structure)

Specs

Wrapper around Focusable.view/2

Arguments can be passed in with either the lens first and data structure second or vice versa. Passing the data structure first allows Focus.view/2 to fit neatly in pipeline operations.

Examples

iex> marge = %{
...>   name: "Marge",
...>   address: %{
...>     street: "123 Fake St.",
...>     city: "Springfield"
...>   }
...> }
iex> address_lens = Lens.make_lens(:address)
iex> address_lens
...> |> Focus.view(marge)
%{street: "123 Fake St.", city: "Springfield"}
iex> marge
...> |> Focus.view(address_lens)
%{street: "123 Fake St.", city: "Springfield"}
Link to this function

view_list(lenses, structure)

Specs

view_list([Focus.Types.optic()], Focus.Types.traversable()) :: [any()]

Given a list of lenses and a structure, apply Focus.view/2 for each lens to the structure.

Examples

iex> homer = %{
...>   name: "Homer",
...>   job: "Nuclear Safety Inspector",
...>   children: ["Bart", "Lisa", "Maggie"]
...> }
iex> lenses = Lens.make_lenses(homer)
iex> [lenses.name, lenses.children]
...> |> Focus.view_list(homer)
["Homer", ["Bart", "Lisa", "Maggie"]]