Last active
August 29, 2015 14:18
-
-
Save turanct/1929e5ac859a22479de4 to your computer and use it in GitHub Desktop.
Monoids for validation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function partial($function, ...$arguments) | |
{ | |
return function() use ($function, $arguments) { | |
$fullArguments = array_merge($arguments, func_get_args()); | |
return call_user_func_array($function, $fullArguments); | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
interface Maybe | |
{ | |
} | |
final class Just implements Maybe | |
{ | |
private $value; | |
public function __construct($value) | |
{ | |
$this->value = $value; | |
} | |
public function get() | |
{ | |
return $this->value; | |
} | |
} | |
final class Nothing implements Maybe | |
{ | |
} | |
function combine(callable $f, Maybe $m1, Maybe $m2) | |
{ | |
if ($m1 instanceof Nothing) { | |
return $m2; | |
} elseif ($m2 instanceof Nothing) { | |
return $m1; | |
} else { | |
return new Just($f($m1->get(), $m2->get())); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require_once __DIR__ . '/higher-order.php'; | |
require_once __DIR__ . '/maybe.php'; | |
/** | |
* lists of validation results are monoids, we only care about the validation errors: | |
* | |
* closure: a list of results + a list of results => a list of results | |
* associativity: ([result1] + [result2]) + [result3] = [result1] + ([result2] + [result3]) | |
* identity: Maybe[result1] + Nothing = Maybe[result1] | |
* | |
* see also: http://fsharpforfunandprofit.com/posts/monoids-without-tears/ | |
*/ | |
function fail($message) | |
{ | |
// lift | |
return new Just(array($message)); | |
} | |
function validateBadWord($badWord, $string) | |
{ | |
if (stristr($string, $badWord)) { | |
return fail('string contains a bad word: ' . $badWord); | |
} else { | |
return new Nothing(); | |
} | |
} | |
function validateLength($maxLength, $string) | |
{ | |
if (strlen($string) > $maxLength) { | |
return fail('string is too long'); | |
} else { | |
return new Nothing(); | |
} | |
} | |
function combineFails(Maybe $f1, Maybe $f2) | |
{ | |
$f = function(array $a, array $b) { | |
return array_merge($a, $b); | |
}; | |
return combine($f, $f1, $f2); | |
} | |
$validationResults = function ($string) { | |
return array_map( | |
function($validate) use ($string) { | |
return $validate($string); | |
}, | |
array( | |
partial(@validateLength, 10), | |
partial(@validateBadWord, 'monad'), | |
partial(@validateBadWord, 'cobol'), | |
) | |
); | |
}; | |
var_dump( | |
array_reduce( | |
$validationResults('cobol has native support for monads'), | |
partial(@combineFails), | |
new Nothing() // Identity | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment