Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lenses

Lenses is an Erlang port of the Haskell library lens.

lens

It currently implements a focused subset of the upstream API.

Lens

type Lens s t a b = forall f. Functor f => (a -> f b) -> (s -> f t)
lens:lens(s -> a, s -> b -> t) -> Lens s t a b

Lens = lens:lens(fun({_, A}) -> A end, fun({C, _}, B) ->  {C, B} end),
?assertEqual(world, getter:view(Lens, {hello, world})),
?assertEqual({hello, another_world}, setter:set(Lens, another_world, {hello, world})).

Traversal

type Traversal s t a b = forall f. Applicative f => (a -> f b) -> (s -> f t)
traversal:traverse() -> forall t. Traversable t => Traversal (t a) (t b) a b

Traversal = traversal:traverse(),
?assertEqual([2, 4], setter:over(Traversal, fun(A) -> A + 1 end, As)).

ISO

type Iso s t a b = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t) 
iso:iso(s -> a, b -> t) -> Iso s t a b
iso:from(Iso s t a b) -> Iso b a t s

Iso = iso:iso(fun(A) -> identity:run(A) end, fun(A) -> identity:identity(A) end),
?assertEqual(3, getter:view(Iso, {identity, 3})),
?assertEqual({identity, 1}, setter:set(Iso, 1, {identity, 3})),
?assertEqual({identity, 3}, getter:view(iso:from(Iso), 3)).

Prism

type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)
prism:prism(b -> t, s -> Either t a) -> Prism s t a b
prism:matching(Prism s t a b, s) -> Either t a
prism:preview(Prism s t a b, s) -> Maybe a
prism:review(Prism s t a b, b) -> t

-include_lib("erlando/include/op.hrl").
Prism = prism:prism(fun(A) -> {cat, A} end, fun({cat, A}) -> {right, A}; (Other) -> {left, Other} end),
Traverse = traversal:traverse(),
Compose = Traverse /'.'/ Prism,
CatsAndDogs = [{cat, kitty}, {dog, snoopy}, {cat, coffee}],
?assertEqual([kitty, coffee], fold:to_list_of(Compose, CatsAndDogs)),
?assertEqual([{cat, {my, kitty}}, {dog, snoopy}, {cat, {my, coffee}}],
              setter:over(Compose, fun(Cat) -> {my, Cat} end, CatsAndDogs)),
?assertEqual({right, kitty}, prism:matching(Prism, {cat, kitty})),
?assertEqual({just, kitty}, prism:preview(Prism, {cat, kitty})),
?assertEqual({cat, kitty}, prism:review(Prism, kitty)).

Getter

type Getting r s a = (a -> Const r a) -> (s -> Const r s)
type Getter s a = forall r. Getting r s a
getter:view(Getting a s a, s) -> a

Fold

fold:to_list_of(Getting [a] s a, s) -> [a]

Setter

type Setter s t a b = (a -> Identity b) -> (s -> Identity t)
setter:over(Setter s t a b, a -> b, s) -> t

TypeClass & Instances

  • function (->) is an instance of Profunctor
  • Const r is an instance of Functor
  • Identity is an Instance of Functor
  • Choice is Profunctor
  • Applicative is Functor
  • Lens is Getter
  • Lens is Traversal
  • Traversal is Setter
  • Traversal is Fold
  • Iso is Lens
  • Iso is Prism
  • Prism is Traversal
  • Getter is Fold

Compose

Lenses can be composed with function composition because

(p a (f b) -> p s (f t)) -> (p x (f y) -> p a (f b)) -> (p x (f y) -> p s (f t))

MakeLenses

-compile({parse_transform, make_lenses}).
-record(state, {hello, world}).
-make_lenses([state, #{module => state}]).

generates

state:hello/0
state:world/0

which represents lenses of #state.hello, #state.world

Laws

User-defined optics are expected to satisfy the corresponding upstream lens laws. The test suite covers the Lens get-put, put-get and put-put laws, Setter identity and composition, Prism review/preview round trips, and Iso inversion.

Releases

Packages

Contributors

Languages