CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-lenses

A lens library for python that enables immutable manipulation of deeply nested data structures

Pending
Overview
Eval results
Files

optics.mddocs/

Optics System

Low-level optics system providing the mathematical foundation for lens operations. The optics system implements different types of optics (Lens, Prism, Traversal, Isomorphism, etc.) that can be composed to create complex data access patterns.

Capabilities

Base Optics Interface

Core interfaces and base classes that define the optics system.

class LensLike:
    """Base interface for all optic types."""
    def kind(self): ...
    def compose(self, other): ...
    def view(self, state): ...
    def over(self, state, func): ...
    def set(self, state, value): ...
    def to_list_of(self, state): ...

class TrivialIso:
    """Identity isomorphism - does nothing."""
    pass

class ComposedLens:
    """Composed optic combining two optics."""
    def __init__(self, lens1, lens2): ...

class Equality:
    """Equality-based optic."""
    pass

class TupleOptic:
    """Combines multiple optic focuses into a tuple."""
    def __init__(self, *optics): ...

Optic Types by Capability

Different optic types providing various levels of access capability.

class Fold:
    """Read-only access to multiple foci."""
    def __init__(self, func: Callable[[A], Iterable[X]]): ...

class Getter:
    """Read-only access to single focus."""
    def __init__(self, getter: Callable[[A], X]): ...

class Setter:
    """Write-only access to foci."""
    pass

class Review:
    """Write-only optic for constructing values."""
    pass

class Traversal:
    """Read-write access to multiple foci."""
    def __init__(self, folder: Callable[[A], Iterable[X]], 
                 builder: Callable[[A, Iterable[Y]], B]): ...

class Lens:
    """Read-write access to single focus."""
    def __init__(self, getter: Callable[[A], X], 
                 setter: Callable[[A, Y], B]): ...

class Prism:
    """Optional read-write access (zero or one focus)."""
    def __init__(self, unpack: Callable[[A], Just[X]], 
                 pack: Callable[[Y], B]): ...

class Isomorphism:
    """Bidirectional conversion between types."""
    def __init__(self, forwards: Callable[[A], X], 
                 backwards: Callable[[Y], B]): ...
    def re(self): ...  # Reverse the isomorphism

Concrete Fold Implementations

Specific fold implementations for read-only traversal.

class IterableFold:
    """Fold over any iterable object."""
    pass

Usage Examples

from lenses.optics import IterableFold
from lenses import lens

# Direct optic usage (advanced)
fold = IterableFold()
data = [1, 2, 3, 4, 5]
values = fold.to_list_of(data)  # [1, 2, 3, 4, 5]

# More commonly used through lens interface
lens.Iter().collect()(data)  # [1, 2, 3, 4, 5]

Concrete Isomorphism Implementations

Isomorphisms for converting between different data representations.

class DecodeIso:
    """String/bytes encoding conversion isomorphism."""
    def __init__(self, encoding: str = "utf-8", errors: str = "strict"): ...

class JsonIso:
    """JSON string parsing isomorphism."""
    pass

class NormalisingIso:
    """Value normalization isomorphism."""
    def __init__(self, setter: Callable[[A], X]): ...

class ErrorIso:
    """Exception-raising isomorphism for debugging."""
    def __init__(self, exception: Exception, message: Optional[str] = None): ...

Usage Examples

from lenses.optics import JsonIso, DecodeIso
from lenses import lens

# JSON isomorphism
json_iso = JsonIso()
json_data = '{"name": "Alice", "age": 30}'
parsed = json_iso.view(json_data)  # {"name": "Alice", "age": 30}

# Through lens interface (more common)
name = lens.Json()["name"].get()(json_data)  # "Alice"

# Decode isomorphism
decode_iso = DecodeIso("utf-8")
byte_data = b"hello"
text = decode_iso.view(byte_data)  # "hello"

Concrete Prism Implementations

Prisms for optional or conditional access patterns.

class FilteringPrism:
    """Prism that filters by predicate."""
    def __init__(self, predicate: Callable[[A], bool]): ...

class InstancePrism:
    """Prism that filters by type."""
    def __init__(self, type_: Type): ...

class JustPrism:
    """Prism for Maybe Just values."""
    pass

Usage Examples

from lenses.optics import FilteringPrism, InstancePrism
from lenses import lens

# Filtering prism
positive_prism = FilteringPrism(lambda x: x > 0)
data = [-1, 2, -3, 4]
positive_values = [positive_prism.to_list_of([x]) for x in data]  # [[], [2], [], [4]]

# Through lens interface (more common)  
positive = lens.Each().Filter(lambda x: x > 0).collect()(data)  # [2, 4]

# Instance prism for type filtering
str_prism = InstancePrism(str)
mixed = [1, "hello", 2.5, "world"]
strings = lens.Each().Instance(str).collect()(mixed)  # ["hello", "world"]

Concrete Setter Implementations

Setters for write-only operations.

class ForkedSetter:
    """Parallel composition of multiple setters."""
    def __init__(self, *setters): ...

Usage Examples

from lenses.optics import ForkedSetter, GetitemLens
from lenses import lens

# Forked setter for parallel updates
fork = ForkedSetter(GetitemLens(0), GetitemLens(2))
data = [1, 2, 3, 4, 5]
updated = fork.set(data, 99)  # [99, 2, 99, 4, 5]

# Through lens interface (more common)
fork_lens = lens.Fork(lens[0], lens[2])
result = fork_lens.set(99)(data)  # [99, 2, 99, 4, 5]

Concrete Traversal Implementations

Traversals for read-write access to multiple foci.

class EachTraversal:
    """Traverse all items in a collection."""
    pass

class ItemsTraversal:
    """Traverse dictionary items as (key, value) pairs."""
    pass

class RecurTraversal:
    """Recursively traverse objects of a specific type."""
    def __init__(self, cls): ...

class RegexTraversal:
    """Traverse string parts matching a regex pattern."""
    def __init__(self, pattern: Pattern, flags: int = 0): ...

class GetZoomAttrTraversal:
    """Traverse attribute, zooming if it's a lens."""
    def __init__(self, name: str): ...

class ZoomAttrTraversal:
    """Traverse lens attribute."""
    def __init__(self, name: str): ...

class ZoomTraversal:
    """Follow bound lens objects."""
    pass

Usage Examples

from lenses.optics import EachTraversal, RecurTraversal
from lenses import lens

# Each traversal
each = EachTraversal()
data = [1, 2, 3]
values = each.to_list_of(data)  # [1, 2, 3]
doubled = each.over(data, lambda x: x * 2)  # [2, 4, 6]

# Recursive traversal
recur = RecurTraversal(int)
nested = [1, [2, 3], [[4]], 5]
all_ints = recur.to_list_of(nested)  # [1, 2, 3, 4, 5]

# Through lens interface (more common)
all_ints_lens = lens.Recur(int).collect()(nested)  # [1, 2, 3, 4, 5]

Concrete Lens Implementations

True lenses providing read-write access to single foci.

class GetattrLens:
    """Lens for object attributes."""
    def __init__(self, name: str): ...

class GetitemLens:
    """Lens for container items."""
    def __init__(self, key: Any): ...

class GetitemOrElseLens:
    """Lens for container items with default values."""
    def __init__(self, key: Any, default: Optional[Y] = None): ...

class ContainsLens:
    """Lens for collection containment as boolean."""
    def __init__(self, item: A): ...

class ItemLens:
    """Lens for dictionary items as (key, value) pairs."""
    def __init__(self, key: Any): ...

class ItemByValueLens:
    """Lens for dictionary items by value."""
    def __init__(self, value: Any): ...

class PartsLens:
    """Converts fold/traversal to lens by collecting parts."""
    def __init__(self, optic): ...

Usage Examples

from lenses.optics import GetitemLens, GetattrLens, ContainsLens
from lenses import lens

# Getitem lens
item_lens = GetitemLens(0)
data = [10, 20, 30]
first = item_lens.view(data)  # 10
updated = item_lens.set(data, 99)  # [99, 20, 30]

# Getattr lens  
from collections import namedtuple
Person = namedtuple('Person', 'name age')
person = Person("Alice", 30)
name_lens = GetattrLens('name')
name = name_lens.view(person)  # "Alice"

# Contains lens
contains_lens = ContainsLens(2)
data = [1, 2, 3]
has_two = contains_lens.view(data)  # True
without_two = contains_lens.set(data, False)  # [1, 3]

# Through lens interface (more common)
first_item = lens[0].get()(data)  # 10
person_name = lens.GetAttr('name').get()(person)  # "Alice"

Optic Composition

How optics compose to create complex access patterns.

def compose_optics(optic1, optic2):
    """Compose two optics into a single optic."""
    return ComposedLens(optic1, optic2)

Composition Examples

from lenses.optics import GetitemLens, EachTraversal
from lenses import lens

# Manual composition (advanced usage)
first_item = GetitemLens(0)
each_item = EachTraversal()
composed = first_item.compose(each_item)

# Through lens interface (recommended)
data = [[1, 2], [3, 4], [5, 6]]
first_each = lens[0].Each().collect()(data)  # [1, 2]

# Complex compositions
nested_access = (lens["users"]
                 .Each()
                 .Filter(lambda u: u.get("active", False))
                 ["profile"]
                 ["name"])

Install with Tessl CLI

npx tessl i tessl/pypi-lenses

docs

core-lenses.md

index.md

lens-constructors.md

optics.md

utility-types.md

tile.json