2017 © Pedro Peláez
 

library functions

Functional interfaces

image

xp-forge/functions

Functional interfaces

  • Monday, February 22, 2016
  • by thekid
  • Repository
  • 2 Watchers
  • 0 Stars
  • 0 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 1 Versions
  • 0 % Grown

The README.md

Functional interfaces

Build Status on TravisCI XP Framework Module BSD Licence Requires PHP 7.0+ Latest Stable Version, (*1)

Utilities for functional programming:, (*2)

  • Closures - Represents a function which takes in an argument and returns a result.
  • Predicates - Represents a function which takes in an argument and returns a boolean.
  • Consumers - Represents a function which takes in an argument and does not return anything.
  • Errors - Provides a factory for handling, rethrowing and suppressing errors
  • Map lookup - Provides a factory for creating closures for map lookups:

Examples

Closure

Instances of the lang.functions.Closure class represent a function which takes in an argument and returns a result., (*3)

use lang\functions\Closure;

$increment= Closure::of(function($val) { return $val + 1; });
$doubleIt= Closure::of(function($val) { return $val * 2; });

$increment->apply(5);                      // = 5 + 1 = 6
$increment->andThen($doubleIt)->apply(5);  // = (5 + 1) * 2 = 12
$increment->butFirst($doubleIt)->apply(5); // = (5 * 2) + 1 = 11

The identity() method returns a closure instance which will return its arguments' value. The following example shows how it is used as the initial value for a reduction on a sequence of filters: If filters is empty, the reduction will return the identity function, otherwise it will combine all given closures using andThen()., (*4)

use lang\functions\Closure;
use util\data\Sequence;

// Implementation @ https://gist.github.com/thekid/92e020b9f5bbc7e9cb5f
class Color {
  public function __construct(int $r, int $g, int $b) { ... }
  public function brighter(): Color { ... }
  public function darker(): Color { ... }
}

class Camera {
  private $filter;

  public function __construct(... $filters) {
    $this->filter= Sequence::of($filters)->reduce(
      Closure::identity(),
      [Closure::class, 'andThen']
    );
  }

  public function snap(Color $input): Color {
    return $this->filter->apply($input);
  }
}

$input= new Color(125, 125, 125);
(new Camera())->snap($input);                            // 125, 125, 125
(new Camera([Color::class, 'brighter']))->snap($input);  // 178, 178, 178

Predicate

Instances of the lang.functions.Predicate class represent a function which takes in an argument and returns a boolean., (*5)

use lang\functions\Predicate;

$isNull= Predicate::of(function($val) { return null === $val; });
$gtZero= Predicate::of(function($val) { return $val > 0; });
$ltFifty= Predicate::of(function($val) { return $val < 50; });

$gtZero->test(5);                          // = 5 > 0 = true
$isNull->negate()->test(1);                // = !(1 === null) = true
$gtZero->and($ltFifty)->test(5);           // = 5 > 0 && 5 < 50 = true
$isNull->or($gtZero)->test(null);          // = null === null || null > 0 = true

Consumer

Instances of the lang.functions.Consumer class represent a function which takes in an argument and does not return anything., (*6)

use lang\functions\Consumer;

$file= ...;
$dump= Consumer::of(function($val) { var_dump($val); });
$write= Consumer::of(function($val) use($file) { $file->write($val); });

$dump->accept(true);                       // Prints "bool(true)"
$dump->andThen($write)->accept(true);      // Prints, then writes to file

if ($simulation) {
  $consumer= Consumer::void();             // Do nothing in simulation
} else if ($debug) {
  $consumer= $write->butFirst($dump);      // In debug mode, log first
} else {
  $consumer= $write;                       // Otherwise, write directly
}
$consumer->accept(true);

Consumers can be conveniently used to create APIs like the one below: You cannot forget to close the resource as you might:, (*7)

use lang\functions\Consumer;

class Resource {
  private $conn;

  private function __construct() { $this->conn= ...; }

  private function close() { $this->conn->close(); }

  public function operation() { ... }

  public static function use(Consumer $consumer) {
    $self= new self();
    try {
      $consumer->accept($self);
    } finally {
      $self->close();
    }
  }
}

Resource::use(Consumer::of(function(Resource $resource) {
  $this->cat->info('Performing operation...')
  $resource->operation();
}));

Errors

For handling errors, closure calls can be wrapped in methods. The lang.functions.Errors factory provides three built-in error handling ways:, (*8)

  • Handle via function: Supply a closure which receives the exception and can decide to either return a value (e.g. a default), to log and/or rethrow.
  • Rethrow: Supply a closure to wrap exceptions in other exceptions.
  • Suppress: Catch exceptions and return null.
use lang\functions\Closure;
use lang\functions\Errors;
use lang\Throwable;

$log= function(Throwable $e) {
  $this->cat->error('Operation failed', $e);
  throw $e;
};

Closure::of($operation)->wrapIn(Errors::handle($log))->apply($param);

Map lookup

The lang.functions.Closures class provides a factory for creating closures for map lookups:, (*9)

use lang\functions\Closures;

$map= ['key' => 'value'];

$get= Closures::forMap($map);
$get->apply('key');         // value
$get->apply('color');       // ***lang.ElementNotFoundException

$find= Closures::forMap($map, null);
$find->apply('key');        // value
$find->apply('color');      // null

Further reading

The Versions

22/02 2016

dev-master

9999999-dev http://xp-framework.net/

Functional interfaces

  Sources   Download

BSD-3-Clause

The Requires

 

The Development Requires

module xp