Source code for lenses.ui

from typing import Callable, Iterable, List, Optional, Type

from .. import optics
from ..typevars import S, T, A, B, X, Y

from .base import BaseUiLens


[docs]class UnboundLens(BaseUiLens[S, T, A, B]): 'An unbound lens is a lens that has not been bound to any state.' __slots__ = ('_optic',) def __init__(self, optic): self._optic = optic def __repr__(self) -> str: return 'UnboundLens({!r})'.format(self._optic)
[docs] def get(self) -> Callable[[S], B]: '''Get the first value focused by the lens. >>> from lenses import lens >>> getter = lens.get() >>> getter([1, 2, 3]) [1, 2, 3] >>> zero_item_getter = lens[0].get() >>> zero_item_getter([1, 2, 3]) 1 ''' def getter(state): return self._optic.to_list_of(state)[0] return getter
[docs] def collect(self) -> Callable[[S], List[B]]: '''Get multiple values focused by the lens. Returns them as a list. >>> from lenses import lens >>> collect_each_first = lens.Each()[0].collect() >>> collect_each_first([(1, 2), (3, 4), (5, 6)]) [1, 3, 5] ''' def getter(state): return self._optic.to_list_of(state) return getter
[docs] def get_monoid(self) -> Callable[[S], B]: '''Get the values focused by the lens, merging them together by treating them as a monoid. See `lenses.typeclass.mappend`. >>> from lenses import lens >>> get_each_monoidally = lens.Each().get_monoid() >>> get_each_monoidally([[], [1], [2, 3]]) [1, 2, 3] ''' def getter(state): return self._optic.view(state) return getter
[docs] def set(self, newvalue: B) -> Callable[[S], T]: '''Set the focus to `newvalue`. >>> from lenses import lens >>> set_item_one_to_four = lens[1].set(4) >>> set_item_one_to_four([1, 2, 3]) [1, 4, 3] ''' def setter(state): return self._optic.set(state, newvalue) return setter
[docs] def set_many(self, new_values: Iterable[B]) -> Callable[[S], T]: '''Set many foci to values taken by iterating over `new_values`. >>> from lenses import lens >>> lens.Each().set_many(range(4, 7))([0, 1, 2]) [4, 5, 6] ''' def setter_many(state): return self._optic.iterate(state, new_values) return setter_many
[docs] def modify(self, func: Callable[[A], B]) -> Callable[[S], T]: '''Apply a function to the focus. >>> from lenses import lens >>> convert_item_one_to_string = lens[1].modify(str) >>> convert_item_one_to_string([1, 2, 3]) [1, '2', 3] >>> add_ten_to_item_one = lens[1].modify(lambda n: n + 10) >>> add_ten_to_item_one([1, 2, 3]) [1, 12, 3] ''' def modifier(state): return self._optic.over(state, func) return modifier
[docs] def construct(self, focus: A) -> S: '''Construct a state given a focus.''' return self._optic.re().view(focus)
[docs] def flip(self) -> 'UnboundLens[A, B, S, T]': '''Flips the direction of the lens. The lens must be unbound and all the underlying operations must be isomorphisms. >>> from lenses import lens >>> json_encoder = lens.Decode().Json().flip() >>> json_encode = json_encoder.get() >>> json_encode(['hello', 'world']) # doctest: +SKIP b'["hello", "world"]' ''' return UnboundLens(self._optic.re())
def __and__( self, other: 'UnboundLens[A, B, X, Y]' ) -> 'UnboundLens[S, T, X, Y]': '''Refine the current focus of this lens by composing it with another lens object. The other lens must be unbound. >>> from lenses import lens >>> first = lens[0] >>> second = lens[1] >>> second_first = second & first >>> get_second_then_first = second_first.get() >>> get_second_then_first([[0, 1], [2, 3]]) 2 ''' if not isinstance(other, UnboundLens): message = 'Cannot compose lens of type {!r}.' raise TypeError(message.format(type(other))) return self._compose_optic(other._optic) def __get__( self, instance: Optional[S], owner: Type ) -> BaseUiLens[S, T, A, B]: if instance is None: return self return BoundLens(instance, self._optic) def _compose_optic( self, optic: optics.LensLike ) -> 'UnboundLens[S, T, X, Y]': return UnboundLens(self._optic.compose(optic))
[docs] def kind(self) -> str: 'Returns the "kind" of the lens.' return self._optic.kind().__name__
add_lens = __and__
class BoundLens(BaseUiLens[S, T, A, B]): 'A bound lens is a lens that has been bound to a specific state.' __slots__ = ('_state', '_optic') def __init__(self, state: S, optic: optics.LensLike) -> None: self._state = state self._optic = optic def __repr__(self) -> str: return 'BoundLens({!r}, {!r})'.format(self._state, self._optic) def get(self) -> B: '''Get the first value focused by the lens. >>> from lenses import bind >>> bind([1, 2, 3]).get() [1, 2, 3] >>> bind([1, 2, 3])[0].get() 1 ''' return self._optic.to_list_of(self._state)[0] def collect(self) -> List[B]: '''Get multiple values focused by the lens. Returns them as a list. >>> from lenses import bind >>> bind([(1, 2), (3, 4), (5, 6)]).Each()[0].collect() [1, 3, 5] ''' return self._optic.to_list_of(self._state) def get_monoid(self) -> B: '''Get the values focused by the lens, merging them together by treating them as a monoid. See `lenses.typeclass.mappend`. >>> from lenses import bind >>> bind([[], [1], [2, 3]]).Each().get_monoid() [1, 2, 3] ''' return self._optic.view(self._state) def set(self, newvalue: B) -> T: '''Set the focus to `newvalue`. >>> from lenses import bind >>> bind([1, 2, 3])[1].set(4) [1, 4, 3] ''' return self._optic.set(self._state, newvalue) def set_many(self, new_values: Iterable[B]) -> T: '''Set many foci to values taken by iterating over `new_values`. >>> from lenses import bind >>> bind([0, 1, 2]).Each().set_many(range(4, 7)) [4, 5, 6] ''' return self._optic.iterate(self._state, new_values) def modify(self, func: Callable[[A], B]) -> T: '''Apply a function to the focus. >>> from lenses import bind >>> bind([1, 2, 3])[1].modify(str) [1, '2', 3] >>> bind([1, 2, 3])[1].modify(lambda n: n + 10) [1, 12, 3] ''' return self._optic.over(self._state, func) def __and__( self, other: UnboundLens[A, B, X, Y] ) -> 'BoundLens[S, T, X, Y]': '''Refine the current focus of this lens by composing it with another lens object. The other lens must be unbound. >>> from lenses import lens, bind >>> first = lens[0] >>> second = bind([[0, 1], [2, 3]])[1] >>> (second & first).get() 2 ''' if not isinstance(other, UnboundLens): message = 'Cannot compose lens of type {!r}.' raise TypeError(message.format(type(other))) return self._compose_optic(other._optic) def _compose_optic( self, optic: optics.LensLike ) -> 'BoundLens[S, T, X, Y]': return BoundLens(self._state, self._optic.compose(optic)) def kind(self) -> str: 'Returns the "kind" of the lens.' return self._optic.kind().__name__ add_lens = __and__ __all__ = ['UnboundLens', 'BoundLens']