Created
October 7, 2022 09:36
-
-
Save mathiasverraes/5c4d116d0ae41468ade5d6ca02fa11b2 to your computer and use it in GitHub Desktop.
Output of my live coding impro at Full Stack Europe 2022
This file contains 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 declare(strict_types=1); | |
// @mathiasverraes | |
// parser is a function that takes some input and returns (either (structured value AND remainder) OR error) | |
// parser is a function that takes some input and returns a Result | |
$a = function ($input) { | |
$parsed = substr($input, 0, 1); | |
$remainder = substr($input, 1); | |
if ($parsed === 'a') return succeed($parsed, $remainder); else return fail("expected a"); | |
}; | |
$char = function (string $char) { | |
return function ($input) use ($char) { | |
$parsed = substr($input, 0, 1); | |
$remainder = substr($input, 1); | |
if ($parsed === $char) return succeed($parsed, $remainder); else return fail("expected $char"); | |
}; | |
}; | |
$seq = function ($p1, $p2) { | |
return function ($input) use ($p1, $p2) { | |
$r1 = $p1($input); | |
if ($r1->isSuccess()) { | |
$r2 = $p2($r1->remainder()); | |
return $r2; | |
} else { | |
return $r1; | |
} | |
}; | |
}; | |
$append = function ($p1, $p2) { | |
return function ($input) use ($p1, $p2) { | |
$r1 = $p1($input); | |
if ($r1->isSuccess()) { | |
$r2 = $p2($r1->remainder()); | |
if ($r2->isSuccess()) { | |
return succeed($r1->parsed() . $r2->parsed(), $r2->remainder()); | |
} | |
return $r2; | |
} else { | |
return $r1; | |
} | |
}; | |
}; | |
$either = function ($p1, $p2) { | |
return function ($input) use ($p1, $p2) { | |
$r1 = $p1($input); | |
if ($r1->isSuccess()) { | |
return $r1; | |
} else { | |
return $p2($input); | |
} | |
}; | |
}; | |
$map = function ($parser, $map) { | |
return function ($input) use ($map, $parser) { | |
$r = $parser($input); | |
if ($r->isSuccess()) { | |
return succeed($map($r->parsed()), $r->remainder()); | |
} else { | |
return $r; | |
} | |
}; | |
}; | |
final class Result | |
{ | |
private $parsed; | |
private $remainder; | |
private $error; | |
private bool $success = false; | |
private function __construct() | |
{ | |
} | |
public function parsed() | |
{ | |
return $this->parsed; | |
} | |
public function remainder() | |
{ | |
return $this->remainder; | |
} | |
public function isSuccess(): bool | |
{ | |
return $this->success; | |
} | |
public function isFail(): bool | |
{ | |
return !$this->success; | |
} | |
public function error() | |
{ | |
return $this->error; | |
} | |
public static function succeed($parsed, $remainder): Result | |
{ | |
$r = (new Result()); | |
$r->success = true; | |
$r->parsed = $parsed; | |
$r->remainder = $remainder; | |
return $r; | |
} | |
public static function fail(string $error): Result | |
{ | |
$r = (new Result()); | |
$r->success = false; | |
$r->error = $error; | |
return $r; | |
} | |
} | |
function fail(string $error) | |
{ | |
return Result::fail($error); | |
} | |
function succeed($parsed, $remainder) | |
{ | |
return Result::succeed($parsed, $remainder); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment