{unctionalStructures
byMarcelloDuarte
@_md
f inPHP
@_md#phpbnl17
Expressinganything
@_md#phpbnl17
@_md#phpbnl17
categorytheory
@_md#phpbnl17
categorytheory
somecoolstructures
somearrows
somelaws
{
@_md#phpbnl17
A B
@_md#phpbnl17
A B
"PHPBenelux" 10
@_md#phpbnl17
A B
"PHPBenelux" 10
@_md#phpbnl17
A B
"PHPBenelux"
f
10
@_md#phpbnl17
B
10
C
true
@_md#phpbnl17
B
10
C
true
@_md#phpbnl17
B
10
C
true
g
@_md#phpbnl17
@_md#phpbnl17
github.com/phunkie/phunkie
@_md#phpbnl17
SEMIGROUPS
@_md#phpbnl17
https://upload.wikimedia.org/wikipedia/commons/c/c2/Falkland_Islands_Penguins_40.jpg
@_md#phpbnl17
combine(1, 2) == 3;
combine("a", "b") == "ab";
combine(true, false) == false;
@_md#phpbnl17
h
@_md#phpbnl17
$f = function(string $a): int {
return strlen($a);
};
@_md#phpbnl17
$f = function(string $a): int {
return strlen($a);
};
$g = function(int $b): bool {
return $b % 2 === 0;
};
@_md#phpbnl17
$f = function(string $a): int {
return strlen($a);
};
$g = function(int $b): bool {
return $b % 2 === 0;
};
$h = combine($f, g);
$h("PHPBenelux") == true;
@_md#phpbnl17
combine($f, g) == compose ($f, $g)
// if $f and $g are functions
@_md#phpbnl17
compose ("strlen", odd, Option, ...)
@_md#phpbnl17
laws
@_md#phpbnl17
combine(combine(1, 2), 3) == combine(1, combine(2, 3))
associativity
@_md#phpbnl17
MONOIDS
@_md#phpbnl17
https://upload.wikimedia.org/wikipedia/commons/c/c2/Falkland_Islands_Penguins_40.jpg
@_md#phpbnl17
$identity = function ($x) {
return $x;
};
A
"PHPBenelux"
i
@_md#phpbnl17
zero(42) == 0;
zero("any string") == "";
zero(true, false) == true;
@_md#phpbnl17
laws
@_md#phpbnl17
combine(combine(1, 2), 3) == combine(1, combine(2, 3))
combine(zero($x), $x) == $x
combine($x, zero($x)) == $x
associativity
(left and right) identity
@_md#phpbnl17
interface Monoid extends Semigroup {

public function zero();
// inherited from Semigroup
public function combine($another);
}
@_md#phpbnl17
interface Monoid extends Semigroup {

public function zero();
// inherited from Semigroup
public function combine($another);
}
class Balance implements Monoid { // ... }
@_md#phpbnl17
$deposit100bucks = function(Balance $b) {
return $b->plus(100);
}



$listOfBalances->foldMap($deposit100bucks);
@_md#phpbnl17
FUNCTORS
@_md#phpbnl17
https://upload.wikimedia.org/wikipedia/commons/3/3b/World_Map_1689.JPG
@_md#phpbnl17
kinds
@_md#phpbnl17
proper
{
@_md#phpbnl17
givemeanumber
@_md#phpbnl17
42givemeanumber
@_md#phpbnl17
givemeaword
@_md#phpbnl17
givemeaword "cabuzle"
@_md#phpbnl17
proper
first-order{
@_md#phpbnl17
givemealist
@_md#phpbnl17
givemealist …
@_md#phpbnl17
givemealist alistofwhat?
@_md#phpbnl17
ImmList(1,2,3)
// List<Int>

ImmList("a thing", "another thing")
// List<String>

@_md#phpbnl17
ImmList(1,2,3)
// List<Int>

ImmList("a thing", "another thing")
// List<String>
@_md#phpbnl17
abstract class Option {}
class Some extends Option {}
class None extends Option {}
@_md#phpbnl17
phunkie > Option(42)
$var0: Option<Int> = Some(42)
phunkie > Option(null)
$var1: None = None




@_md#phpbnl17
phunkie > $f = compose(mayBeRubish, Option)

phunkie > $f(42)
$var0: None = None




@_md#phpbnl17
proper
first-order
higherorder
{
@_md#phpbnl17
function fmap(Mappable $mappable, callable $f) {
return $mappable->map($f);
}
@_md#phpbnl17
$listOfWords = ImmList("guacamole", "nose", "penguin");
$lengths = fmap ("strlen") ($listOfWords);
// List (9, 4, 7)
@_md#phpbnl17
$maybeSomeGuaca = Option("guacamole");
$length = fmap ("strlen") ($maybeSomeGuaca);
// Some (9)
@_md#phpbnl17
$maybeSomeGuaca = Option("guacamole");
$length = fmap ("strlen") ($maybeSomeGuaca);
// Some (9)
$maybeSomeGuaca = Option(null);
$length = fmap ("strlen") ($maybeSomeGuaca);



// None
@_md#phpbnl17
// Already Mappable in Phunkie
ImmList
Option
Function1
Validations (Either)
// Planned
ImmMap
ImmSet
Tuples (inc. Pair)
@_md#phpbnl17
laws
@_md#phpbnl17
$fa == fmap(identity)($fa)
fmap(compose($f, $g))($fa) == fmap($g)(fmap($f)($fa))
covariant identity
covariant composition
@_md#phpbnl17
APPLICATIVE
@_md#phpbnl17
https://upload.wikimedia.org/wikipedia/commons/5/5c/Brick_and_block_laying.jpg
@_md#phpbnl17
interface Apply extends Functor

{
public function apply($ff);

public function map2($fb, callable $f);

}
interface Applicative extends Apply

{

public function pure($a);

}
@_md#phpbnl17
/**
* @param A $a
* @return FirstOrderKind<A>
*/
function pure($a)
@_md#phpbnl17
/**
* @param A $a
* @return FirstOrderKind<A>
*/
function pure($a)
Option()->pure(42);
// Some(42)
@_md#phpbnl17
/**
* @param A $a
* @return FirstOrderKind<A>
*/
function pure($a)
Option()->pure(42);
// Some(42)
ImmList()->pure(42);
// ImmList(42)
@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
$increment = function($x){ return $x + 1;};


@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
Some(1)->apply(Some($increment));
@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
Some(1)->apply(Some($increment));
// Some(2)

@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
Some(1)->apply(Some($increment));
// Some(2)

None()->apply(Some($increment));

@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
Some(1)->apply(Some($increment));
// Some(2)

None()->apply(Some($increment));

// None
@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
Some(1)->apply(Some($increment));
// Some(2)

None()->apply(Some($increment));

// None
ImmList(1,2,3)->apply(ImmList($increment));

@_md#phpbnl17
/**
* @param FirstOrderKind<callable<A,B>> $ff
* @return FirstOrderKind<B>
*/
function apply($ff)
Some(1)->apply(Some($increment));
// Some(2)

None()->apply(Some($increment));

// None
ImmList(1,2,3)->apply(ImmList($increment));

// ImmList(2,3,4)
@_md#phpbnl17
/**
* @param FirstOrderKind<B> $fb
* @param (A, B) => C $
* @return FirstOrderKind<C>
*/
function map2($fb, callable $f)
@_md#phpbnl17
/**
* @param FirstOrderKind<B> $fb
* @param (A, B) => C $
* @return FirstOrderKind<C>
*/
function map2($fb, callable $f)
Some(1)->map2(Some(2), function($x, $y) { return $x + $y; });;
@_md#phpbnl17
/**
* @param FirstOrderKind<B> $fb
* @param (A, B) => C $
* @return FirstOrderKind<C>
*/
function map2($fb, callable $f)
Some(1)->map2(Some(2), function($x, $y) { return $x + $y; });;
@_md#phpbnl17
/**
* @param FirstOrderKind<B> $fb
* @param (A, B) => C $
* @return FirstOrderKind<C>
*/
function map2($fb, callable $f)
Some(1)->map2(Some(2), function($x, $y) { return $x + $y; });;
// Some(3)

@_md#phpbnl17
/**
* @param FirstOrderKind<B> $fb
* @param (A, B) => C $
* @return FirstOrderKind<C>
*/
function map2($fb, callable $f)
Some(1)->map2(Some(2), function($x, $y) { return $x + $y; });;
// Some(3)

ImmList(1,2)->map2(ImmList(4,5),
function($x, $y) { return $x + $y; });

@_md#phpbnl17
/**
* @param FirstOrderKind<B> $fb
* @param (A, B) => C $
* @return FirstOrderKind<C>
*/
function map2($fb, callable $f)
Some(1)->map2(Some(2), function($x, $y) { return $x + $y; });;
// Some(3)

ImmList(1,2)->map2(ImmList(4,5),
function($x, $y) { return $x + $y; });

// ImmList(5,6,6,7)
@_md#phpbnl17
laws
@_md#phpbnl17
$fa->apply($fa->pure(identity)) == $fa
$fa->pure($a)->fa->apply($fa->pure($f)) ==

$fa->pure($f($a))
identity
homomorphism
@_md#phpbnl17
$fa->pure($a)->apply ==

$fab->apply($fa->pure(function($f)use($a){return $f($a)}))
$fa->map($f) == $fa->apply($fa->pure($f))
interchange
map
@_md#phpbnl17
whywouldyoueveruseafunctor?
@_md#phpbnl17
weakertypesaremorepredictable
@_md#phpbnl17
$xs = fmap (ImmList(1,2,3)) ($f);
echo $xs->length;
@_md#phpbnl17
MONADS
@_md#phpbnl17
https://upload.wikimedia.org/wikipedia/commons/b/bd/Golden_tabby_and_white_kitten_n01.jpg
@_md#phpbnl17
interface FlatMap extends Functor

{
public function flatMap(callable $f);

}
interface Monad extends FlatMap

{

public function flatten();

}
@_md#phpbnl17
/**
* @param (A) -> FirstOrderKind<B> $a
* @return FirstOrderKind<B>
*/
function flatMap($a)
@_md#phpbnl17
/**
* @param (A) -> FirstOrderKind<B> $a
* @return FirstOrderKind<B>
*/
function flatMap($a)
Option(42)->flatMap(function($x) { return Some($x + 1); });
@_md#phpbnl17
/**
* @param (A) -> FirstOrderKind<B> $a
* @return FirstOrderKind<B>
*/
function flatMap($a)
Option(42)->flatMap(function($x) { return Some($x + 1); });
@_md#phpbnl17
/**
* @param (A) -> FirstOrderKind<B> $a
* @return FirstOrderKind<B>
*/
function flatMap($a)
Option(42)->flatMap(function($x) { return Some($x + 1); });
@_md#phpbnl17
/**
* @param (A) -> FirstOrderKind<B> $a
* @return FirstOrderKind<B>
*/
function flatMap($a)
Option(42)->flatMap(function($x) { return Some($x + 1); });
// Some(43)
@_md#phpbnl17
/**
* @param (A) -> FirstOrderKind<B> $a
* @return FirstOrderKind<B>
*/
function flatMap($a)
Option(42)->flatMap(function($x) { return Some($x + 1); });
// Some(43)
ImmList(1,2,3)->flatMap(function($x) {
return Option($x % 2 === 0 ? null : $x); });
// ImmList(1,3)
@_md#phpbnl17
/**
* @return FirstOrderKind<B>
*/
function flatten()
Some(Some(42))->flatten();
// Some(42)
@_md#phpbnl17
/**
* @param (A) -> FirstOrderKind<B> $a
* @return FirstOrderKind<B>
*/
function flatMap($a)
Option(42)->flatMap(function($x) { return Some($x + 1); });
// Some(43)
ImmList(1,2,3)->flatMap(function($x) {
return Option($x % 2 === 0 ? null : $x); });
// ImmList(1,3)
@_md#phpbnl17
laws
@_md#phpbnl17
$fa->flatMap($f)->flatMap($g) == $fa->flatMap(function($a) use ($f,$g) {
return $f($a)->flatMap( function($b) use ($g) { return $g($b); } ) ;})
$fa->pure($a)->flatMap($f) == $f($a)
associativity
right and left identity
$fa->flatMap(function($a) use ($fa) { return $fa-
>pure($a); }) == $fa;
@_md#phpbnl17
monadsyntaxsugar
@_md#phpbnl17
function repl($state)

{

return read()->

flatMap(evaluate)->

flatMap(andPrint)->

flatMap(loop)

->run($state);

}
def repl(state) =

for {
(s,input) <- read

(s,result)<- evaluate

s <- andPrint

s <- loop

} yield s

@_md#phpbnl17
monadcomposability
@_md#phpbnl17
f(A $a): M<B>



g(B $b): M<C>
f(a) ~= M<B>

f(a) map g ~= M<M<C>>


f(a) ~= M<B>

f(a) map g ~= M<M<C>>


urgh!
@_md#phpbnl17
butyoucancomposethemonad’sfunctions!


flatten f(a) map g ~= M<C>


@_md#phpbnl17
VALIDATIONS
@_md#phpbnl17
http://www.sbs.com.au/topics/sites/sbs.com.au.topics/files/gettyimages-470309868.jpg
@_md#phpbnl17
abstract class Validation {}
class Success extends Validation {}
class Failure extends Validation {}
@_md#phpbnl17
phunkie > Success(42)
$var0: Validation<E, Int> = Success(42)
phunkie > Failure("nay")
$var0: Validation<String, A> = Failure("nay")




@_md#phpbnl17
phunkie > Either("nay")(42)
$var0: Validation<E, Int> = Success(42)
phunkie > Either("nay")(null)
$var0: Validation<String, A> = Failure("nay")




@_md#phpbnl17
marcelloduarte
@PhunkiePhp
{
@_md#phpbnl17
thanks
{bit.ly/inviqa-contact bit.ly/inviqa-careers
you!
@_md#phpbnl17
credits
https://upload.wikimedia.org/wikipedia/commons/c/c2/Falkland_Islands_Penguins_40.jpg
{https://upload.wikimedia.org/wikipedia/commons/3/3b/World_Map_1689.JPG
https://upload.wikimedia.org/wikipedia/commons/5/5c/Brick_and_block_laying.jpg
https://upload.wikimedia.org/wikipedia/commons/b/bd/Golden_tabby_and_white_kitten_n01.jpg
@_md#phpbnl17
Questions?


joind.in/talk/75f65
?

Functional Structures in PHP