phunkie

Lenses

Lenses are a functional programming abstraction that provides a way to focus on a specific part of a data structure and perform operations on it. In Phunkie, lenses offer a composable way to view and modify nested data structures.

What is a Lens?

A lens consists of two functions:

class Lens {
    public function get($a);        // Gets the focused value
    public function set($b, $a);    // Sets a new value
    public function mod($f, $a);    // Modifies the focused value using a function
}

Core Operations

get

Retrieves the focused value:

$userNameLens = new Lens(
    fn(User $user) => $user->getName(),
    fn(Name $name, User $user) => $user->copy(["name" => $name])
);
$name = $userNameLens->get($user); // Gets user's name

set

Updates the focused value:

$newUser = $userNameLens->set(new Name("Chuck Norris"), $user);

mod

Modifies the focused value using a function:

$upperCaseName = $userNameLens->mod(
    fn(Name $name) => new Name(strtoupper($name->getName())), 
    $user
);

Lens Composition

Lenses can be composed to focus on deeply nested structures:

$lenses = makeLenses("address", "country", "code");
$codeLens = combine($lenses->address, $lenses->country, $lenses->code);

$countryCode = $codeLens->get($user); // Gets nested country code

Lens Laws

Lenses must satisfy three fundamental laws:

  1. Identity Law: Getting and then setting back the same value changes nothing
    $lens->set($lens->get($a), $a) === $a
    
  2. Retention Law: Setting a value and then getting it returns the value that was set
    $lens->get($lens->set($b, $a)) === $b
    
  3. Double Set Law: Setting twice is the same as setting once
    $lens->set($c, $lens->set($b, $a)) === $lens->set($c, $a)
    

Built-in Lenses

Phunkie provides several built-in lens constructors:

Common Use Cases

  1. Object Property Access
    $lenses = makeLenses("name");
    $userName = $lenses->name->get($user);
    
  2. Nested Data Structures
    $lenses = makeLenses("address", "street");
    $streetLens = combine($lenses->address, $lenses->street);
    
  3. Collection Manipulation
    $mapLens = member("key");
    $value = $mapLens->get($immMap);
    

Best Practices

  1. Use lenses for complex data structures
  2. Compose lenses for deep nesting
  3. Verify lens laws for custom implementations
  4. Use makeLenses() for common property access
  5. Leverage lens composition for reusability

Implementation Notes