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

utility-types.mddocs/

Utility Types

Supporting types and systems that enhance the lens library's functionality, including Maybe monad for optional values, type class system for functional programming patterns, and hooks system for extending support to custom data types.

Capabilities

Maybe Type System

Optional value handling inspired by functional programming, providing safe operations on values that may or may not exist.

class Just:
    """Container for a value that exists."""
    def __init__(self, item: A) -> None: ...
    
    def map(self, fn: Callable[[A], B]) -> Just[B]:
        """Apply function to contained value."""
    
    def maybe(self, guard: B) -> Union[A, B]:
        """Extract value or return guard if Nothing."""
    
    def unwrap(self) -> A:
        """Extract value (raises if Nothing)."""
    
    def is_nothing(self) -> bool:
        """Check if this is Nothing."""
    
    def __add__(self, other: Just[A]) -> Just[A]: ...
    def __eq__(self, other: object) -> bool: ...
    def __iter__(self) -> Iterator[A]: ...

class Nothing(Just):
    """Empty container representing no value."""
    def __init__(self) -> None: ...
    
    def map(self, fn: Callable[[A], B]) -> Just[B]:
        """Always returns Nothing."""
    
    def maybe(self, guard: B) -> Union[A, B]:
        """Always returns guard."""
    
    def unwrap(self) -> A:
        """Always raises ValueError."""
    
    def is_nothing(self) -> bool:
        """Always returns True."""

Usage Examples

from lenses.maybe import Just, Nothing

# Creating Maybe values
some_value = Just(42)
no_value = Nothing()

# Safe operations
result1 = some_value.map(lambda x: x * 2)  # Just(84)
result2 = no_value.map(lambda x: x * 2)   # Nothing()

# Extracting values safely
value1 = some_value.maybe(0)  # 42
value2 = no_value.maybe(0)    # 0 (guard value)

# Checking for values
print(some_value.is_nothing())  # False
print(no_value.is_nothing())    # True

# Unwrapping (dangerous)
actual_value = some_value.unwrap()  # 42
# no_value.unwrap()  # Raises ValueError

# Used with lenses
from lenses import lens
data = [Just(1), Nothing(), Just(3), Nothing(), Just(5)]
values = lens.Each().Just().collect()(data)  # [1, 3, 5]

Type Class System

Functional programming type classes providing generic operations for different data types.

# Monoid operations
def mempty(monoid: Any) -> Any:
    """Get the empty/identity value for a monoid type."""

def mappend(monoid: Any, other: Any) -> Any:
    """Combine two monoid values."""

# Functor operations  
def fmap(functor: Any, func: Callable[[Any], Any]) -> Any:
    """Apply function inside a functor context."""

# Applicative operations
def pure(applicative: Any, item: B) -> Any:
    """Wrap a value in an applicative context."""

def apply(applicative: Any, func: Any) -> Any:
    """Apply wrapped function to wrapped value."""

Built-in Type Support

# Monoid instances for built-in types
mempty(0)        # -> 0 (int)
mempty("")       # -> "" (str) 
mempty([])       # -> [] (list)
mempty({})       # -> {} (dict)
mempty((1, 2))   # -> (0, 0) (tuple)

# Mappend instances
mappend(1, 2)           # -> 3 (int addition)
mappend("a", "b")       # -> "ab" (str concatenation)
mappend([1], [2])       # -> [1, 2] (list concatenation)
mappend({"a": 1}, {"b": 2})  # -> {"a": 1, "b": 2} (dict merge)

# Functor instances
fmap([1, 2, 3], lambda x: x * 2)     # -> [2, 4, 6] (list)
fmap((1, 2, 3), lambda x: x * 2)     # -> (2, 4, 6) (tuple)

# Applicative instances  
pure([], 42)                  # -> [42] (list)
apply([1, 2], [lambda x: x * 2, lambda x: x + 1])  # -> [2, 4, 2, 3]

Usage Examples

from lenses.typeclass import mempty, mappend, fmap

# Working with monoids
empty_list = mempty([1, 2, 3])  # []
combined = mappend([1, 2], [3, 4])  # [1, 2, 3, 4]

# String concatenation through mappend
greeting = mappend("Hello, ", "World!")  # "Hello, World!"

# Dictionary merging
config1 = {"debug": True, "port": 8080}
config2 = {"host": "localhost", "port": 3000}
merged = mappend(config1, config2)  # {"debug": True, "port": 3000, "host": "localhost"}

# Functor mapping  
squared = fmap([1, 2, 3, 4], lambda x: x ** 2)  # [1, 4, 9, 16]

# Used internally by lenses for monoid operations
from lenses import lens
data = [[], [1], [2, 3]]
combined_lists = lens.Each().get_monoid()(data)  # [1, 2, 3]

Const Functor

Constant functor used internally for lens getting operations.

class Const:
    """Functor that ignores the wrapped type and preserves constant value."""
    def __init__(self, item: C) -> None: ...
    
    def map(self, func: Callable[[A], B]) -> Const[C, B]:
        """Ignores function, returns Const with same value."""
    
    def pure(self, item: D) -> Const[D, B]:
        """Creates empty Const."""
    
    def apply(self, fn: Const[C, Callable[[A], B]]) -> Const[C, B]:
        """Combines constant values using mappend."""
    
    def unwrap(self) -> C:
        """Extract the constant value."""
    
    def __eq__(self, other: object) -> bool: ...

Usage Examples

from lenses.const import Const

# Const preserves values through transformations
const_val = Const(42)
mapped = const_val.map(lambda x: x * 1000)  # Still Const(42)
print(mapped.unwrap())  # 42

# Used internally by lens operations
# This is mostly internal to the lens library

Identity Functor

Identity wrapper functor used internally for lens setting operations.

class Identity:
    """Simple wrapper functor that preserves identity."""
    def __init__(self, item: A) -> None: ...
    def unwrap(self) -> A: ...
    def map(self, func: Callable[[A], B]) -> Identity[B]: ...

Hooks System

Extension system allowing custom data types to work with lenses.

# Core hook functions (using singledispatch)
def contains_add(container, item):
    """Add item to container."""

def contains_remove(container, item):
    """Remove item from container."""

def from_iter(prototype, iterator):
    """Reconstruct object from iterator."""

def setattr(obj, name, value):
    """Set object attribute."""

def setitem(obj, key, value):
    """Set container item."""

def to_iter(obj):
    """Convert object to iterator."""

Extending with Custom Types

from lenses.hooks import from_iter, to_iter
from functools import singledispatch

# Example: Adding support for custom collection type
class MyList:
    def __init__(self, items):
        self._items = list(items)
    
    def __iter__(self):
        return iter(self._items)

# Register hooks for your type
@from_iter.register(MyList)
def _mylist_from_iter(prototype, iterator):
    return MyList(iterator)

@to_iter.register(MyList)  
def _mylist_to_iter(obj):
    return iter(obj._items)

# Now MyList works with lenses
from lenses import lens
my_data = MyList([1, 2, 3, 4])
doubled = lens.Each().modify(lambda x: x * 2)(my_data)  # MyList([2, 4, 6, 8])

Pyrsistent Integration

Optional integration with the pyrsistent library for enhanced immutable data structures.

# Automatic registration when pyrsistent is available
# Supports: PVector, PList, PMap, PSet, etc.

# No additional imports needed if pyrsistent is installed
# pip install pyrsistent

Usage Examples

# With pyrsistent installed
import pyrsistent as pyr
from lenses import lens

# Works automatically with pyrsistent collections
plist = pyr.v(1, 2, 3, 4)  # PVector
doubled = lens.Each().modify(lambda x: x * 2)(plist)  # PVector([2, 4, 6, 8])

pmap = pyr.m(a=1, b=2, c=3)  # PMap  
incremented = lens.Values().modify(lambda x: x + 1)(pmap)  # PMap({'a': 2, 'b': 3, 'c': 4})

Functorisor

Advanced functor adapter utilities for internal lens operations.

class Functorisor:
    """Functor adapter for complex lens operations."""
    # Internal implementation details
    # Not typically used directly by end users

Method Shortcuts

The lens system provides convenient method shortcuts for common operations.

# Available on lens objects:
# call_methodname(*args, **kwargs) - shortcut for call('methodname', *args, **kwargs)
# call_mut_methodname(*args, **kwargs) - shortcut for call_mut('methodname', *args, **kwargs)

Usage Examples

from lenses import lens

# Method call shortcuts
data = ['hello', 'world', 'python']

# Regular method calls
uppercased1 = lens.Each().call('upper')(data)  # ['HELLO', 'WORLD', 'PYTHON']

# Shortcut syntax
uppercased2 = lens.Each().call_upper()(data)   # ['HELLO', 'WORLD', 'PYTHON']

# Mutable method shortcuts
data = [[3, 1, 2], [6, 4, 5]]
sorted_data = lens.Each().call_mut_sort()(data)  # [[1, 2, 3], [4, 5, 6]]

Arithmetic and Comparison Operations

Lens objects support arithmetic and comparison operations through the modify interface.

# Arithmetic operations (via modify)
lens_obj + value    # Equivalent to lens_obj.modify(lambda x: x + value)
lens_obj - value    # Equivalent to lens_obj.modify(lambda x: x - value)  
lens_obj * value    # Equivalent to lens_obj.modify(lambda x: x * value)
lens_obj / value    # Equivalent to lens_obj.modify(lambda x: x / value)
# ... and many more operators

# Comparison operations
lens_obj == value   # Equivalent to lens_obj.modify(lambda x: x == value)
lens_obj < value    # Equivalent to lens_obj.modify(lambda x: x < value)
# ... and other comparison operators

Usage Examples

from lenses import lens

# Arithmetic operations
data = [1, 2, 3, 4, 5]
incremented = (lens.Each() + 1)(data)        # [2, 3, 4, 5, 6]  
doubled = (lens.Each() * 2)(data)            # [2, 4, 6, 8, 10]

# Comparison operations
greater_than_3 = (lens.Each() > 3)(data)     # [False, False, False, True, True]

# Bitwise operations (special case)
data = [1, 2, 3, 4]
bitwise_result = lens.Each().bitwise_and(5)(data)  # [1, 0, 1, 4]

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