Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Lens

articles/lens.livemd

Lens

Setup

https://github.com/obrok/lens

Mix.install([{:lens, "~> 1.0.0"}])

Examples

data = %{
  main_widget: %{
    size: 200.5,
    subwidgets: [%{size: 120, subwidgets: [%{size: 200, subwidgets: []}]}]
  },
  other_widgets: [
    %{size: 16.5, subwidgets: [%{size: 120, subwidgets: []}]},
    %{size: 160.5, subwidgets: []},
    %{size: 121.9, subwidgets: []}
  ]
}
lens =
  Lens.both(
    Lens.key(:main_widget),
    Lens.key(:other_widgets) |> Lens.all()
  )
  |> Lens.seq_both(Lens.recur(Lens.key(:subwidgets) |> Lens.all()))
  |> Lens.key(:size)
  |> Lens.filter(&(&1 > 100))
Lens.to_list(lens, data)
Lens.map(lens, data, &round/1)
Lens.key(:other_widgets) |> Lens.all() |> Lens.key(:size) |> Lens.to_list(data)

Kernel functions for nested structure

앗, nested structure 를 편하게 다루는 코드는 외부 라이브러리만 있는줄 알았는데, nested structure 를 BIF 가 있었다.

  • Kernel.get_and_update_in
  • Kernel.get_in
  • Kernel.pop_in
  • Kernel.put_in
  • Kernel.update_in
  • Access.all
  • Access.key

momenti-elixir 프로젝트에서 이미 사용된 적이 있다.

lens 는 accessor 들을 array 가 아닌, 함수들을 합성해서 생성한다.

> Elixir’s get_in/update_in on steroids. - https://yapee.svbtle.com/nested-data-structures-with-lens

data |> get_in([:main_widget, :size])
data |> get_and_update_in([:main_widget, :size], &{&1, &1 * 2})
data |> get_in([Access.key(:other_widgets)])

Access.all, Access.key/1 를 조합해서 array of struct 접근도 가능하다.

get_in(data, [Access.key(:other_widgets), Access.all(), Access.key(:size)])

Practice

Lens.all() |> Lens.key(:val) |> Lens.to_list([%{val: 10}, %{val: 20}, %{val: 30}])
import Integer

Lens.all() |> Lens.filter(&is_odd/1) |> Lens.to_list(1..10)
Lens.key(:a) |> Lens.key(:b) |> Lens.one!(%{a: %{b: 20}})
Lens.seq(Lens.key(:a), Lens.key(:b)) |> Lens.one!(%{a: %{b: 20}})