All Projects → obrok → Lens

obrok / Lens

Licence: mit
A utility for working with nested data structures.

Programming Languages

elixir
2628 projects

Projects that are alternatives of or similar to Lens

hawkweed
Yet another implementation of missing functions for Python
Stars: ✭ 20 (-80.77%)
Mutual labels:  functional, datastructures
Pareto.js
An extremely small, intuitive and fast functional utility library for JavaScript
Stars: ✭ 254 (+144.23%)
Mutual labels:  utility, functional
Pyrsistent
Persistent/Immutable/Functional data structures for Python
Stars: ✭ 1,621 (+1458.65%)
Mutual labels:  datastructures, functional
Pydash
The kitchen sink of Python utility libraries for doing "stuff" in a functional way. Based on the Lo-Dash Javascript library.
Stars: ✭ 728 (+600%)
Mutual labels:  utility, functional
rudash
Rudash - Lodash for Ruby Apps
Stars: ✭ 27 (-74.04%)
Mutual labels:  utility, functional
peds
Type safe persistent/immutable data structures for Go
Stars: ✭ 57 (-45.19%)
Mutual labels:  functional, datastructures
Umbrella
"A collection of functional programming libraries that can be composed together. Unlike a framework, thi.ng is a suite of instruments and you (the user) must be the composer of. Geared towards versatility, not any specific type of music." — @loganpowell via Twitter
Stars: ✭ 2,186 (+2001.92%)
Mutual labels:  datastructures, functional
Funky
Funky is a functional utility library written in Objective-C.
Stars: ✭ 41 (-60.58%)
Mutual labels:  utility, functional
Dataframe Js
A javascript library providing a new data structure for datascientists and developpers
Stars: ✭ 376 (+261.54%)
Mutual labels:  datastructures, functional
Remeda
A utility library for JavaScript and TypeScript.
Stars: ✭ 774 (+644.23%)
Mutual labels:  utility, functional
Repository
个人学习知识库涉及到数据仓库建模、实时计算、大数据、Java、算法等。
Stars: ✭ 92 (-11.54%)
Mutual labels:  datastructures
Gemma
A lightweight CSS library.
Stars: ✭ 94 (-9.62%)
Mutual labels:  functional
Date And Time
A Minimalist DateTime utility for Node.js and the browser
Stars: ✭ 99 (-4.81%)
Mutual labels:  utility
Async Ray
Provide async/await callbacks for every, find, findIndex, filter, forEach, map, reduce, reduceRight and some methods in Array.
Stars: ✭ 102 (-1.92%)
Mutual labels:  utility
Datascience
It consists of examples, assignments discussed in data science course taken at algorithmica.
Stars: ✭ 92 (-11.54%)
Mutual labels:  datastructures
Cron4s
Cross-platform CRON expression parsing for Scala
Stars: ✭ 99 (-4.81%)
Mutual labels:  functional
Cracking The Coding Interview
Tests, Questions and Solutions from Cracking the Coding Interview
Stars: ✭ 91 (-12.5%)
Mutual labels:  datastructures
Bash Utility
Bash library which provides utility functions and helpers for functional programming in Bash.
Stars: ✭ 92 (-11.54%)
Mutual labels:  utility
Sharlayan
Visit us on Discord! https://discord.gg/aCzSANp
Stars: ✭ 91 (-12.5%)
Mutual labels:  utility
Machina
Network capture library for realtime TCP/IP decoding from a windows application. Includes an extension library to support FFXIV data capture.
Stars: ✭ 102 (-1.92%)
Mutual labels:  utility

Lens

Build Status Hex.pm Hex.pm

A utility for working with nested data structures. Take a look at Nested data structures with functional lenses for a gentler introduction. Note that the blogpost was written using version 0.3.1 and there have been some API changes since then - see Upgrading for details.

Installation

The package can be installed by adding lens to your list of dependencies in mix.exs:

def deps do
  [
    {:lens, "~> 1.0.0"}
  ]
end

Upgrading

From pre-0.6.0

In 0.6.0 the function Lens.get got removed. The reason was that it was very easy to create a bug where a list was treated as a single element or vice-versa. Wherever you used Lens.get you now should either use Lens.one! if the invocation should always return exactly one element (this will crash if there is any other number of elements) or Lens.to_list and match on the result if you want to behave differently for different numbers of elements.

From pre-0.5.0

In 0.5.0 the function satisfy got renamed to filter while the previous version of filter was removed. The reason was that with the new arrangement there is a matching pair of filter/reject functions, and this should be more intuitive. Wherever you used Lens.filter(predicate) you can now use Lens.filter(Lens.all(), predicate).

Example

Lens allows you to separate which parts of a complex data structure need to be processed from the actual processing. Take the following:

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: []},
  ]
}

Let's say we're interested in the sizes of all widgets (be they the main widget or other widgets) that are larger than 100. We can construct a Lens object that describes these locations in the datastructure the following way:

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

Given that we can:

  • Extract all the relevant data
iex> Lens.to_list(lens, data)
[200.5, 160.5, 121.9, 120, 200, 120]
  • Update the described locations in the data structure
iex> Lens.map(lens, data, &round/1)
%{main_widget: %{size: 201,
    subwidgets: [%{size: 120, subwidgets: [%{size: 200, subwidgets: []}]}]},
  other_widgets: [%{size: 16.5, subwidgets: [%{size: 120, subwidgets: []}]},
   %{size: 161, subwidgets: []}, %{size: 122, subwidgets: []}]}
  • Simultaneously update and return something from every location in the data
iex> Lens.get_and_map(lens, data, fn size -> {size, round(size)} end)
{[200.5, 160.5, 121.9, 120, 200, 120],
 %{main_widget: %{size: 201,
     subwidgets: [%{size: 120, subwidgets: [%{size: 200, subwidgets: []}]}]},
   other_widgets: [%{size: 16.5, subwidgets: [%{size: 120, subwidgets: []}]},
    %{size: 161, subwidgets: []}, %{size: 122, subwidgets: []}]}}

Lenses are also compatible with Access and associated Kernel functions:

iex> get_in([1, 2, 3], [Lens.all() |> Lens.filter(&Integer.is_odd/1)])
[1, 3]
iex> update_in([1, 2, 3], [Lens.all() |> Lens.filter(&Integer.is_odd/1)], fn x -> x + 1 end)
[2, 2, 4]
iex> get_and_update_in([1, 2, 3], [Lens.all() |> Lens.filter(&Integer.is_odd/1)], fn x -> {x - 1, x + 1} end)
{[0, 2], [2, 2, 4]}

Formatting

Normally, mix format will change definitions like:

deflens a_lens(), do: some() |> implementation()
deflensp a_private_lens(), do: some() |> implementation()

into:

deflens(a_lens(), do: some() |> implementation())
deflensp(a_private_lens(), do: some() |> implementation())

To avoid this, you can import lens's formatter settings in your formatter.exs:

# my_app/.formatter.exs
[
  import_deps: [:lens]
]
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].