Skip to content

Instantly share code, notes, and snippets.

@turanct
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save turanct/1929e5ac859a22479de4 to your computer and use it in GitHub Desktop.
Save turanct/1929e5ac859a22479de4 to your computer and use it in GitHub Desktop.
Monoids for validation
<?php
function partial($function, ...$arguments)
{
return function() use ($function, $arguments) {
$fullArguments = array_merge($arguments, func_get_args());
return call_user_func_array($function, $fullArguments);
};
}
<?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()));
}
}
<?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