Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php error_reporting(E_ALL & ~E_NOTICE);
- /* ===== funky.php =====
- PHP is painfully verbose. This library is an
- attempt at combating that verbosity by introducing
- functional concepts.
- This library aims to be self documenting, and is
- best understood by reading it top to bottom with
- this file loaded in a interactive interpreter.
- */
- /* Unlike most other languages, this is a syntax error in PHP:
- $f (1) (2);
- However, this is perfectly valid:
- $k = $f (1); $k (2);
- Fortunatly, you are allowed to fetch something from a 2D array like this:
- $arr [1] [2];
- So let's exploit that!
- */
- class Funky implements ArrayAccess {
- private $f;
- function __construct ($f) { $this->f = $f; }
- // called when you do: f [x]
- function offsetGet ($x) {
- $f = $this->f; // Mandatory unboxing boilerplate
- return $f($x);
- }
- // Absolutely 100% required boilerplate code
- function offsetExists ($a) {}
- function offsetSet ($a,$b) {}
- function offsetUnset ($a) {}
- // Allows you to call our class like a regular function to
- // pass it multiple valus: f (1, 2) [3]
- function __invoke (...$args) {
- $f = $this;
- foreach ($args as $x) $f = $f [$x];
- return $f;
- }
- /* Allows you to do function composition like this:
- add [2] -> add [3]
- We could technically get to use dots for function
- composition by overriding the toString function,
- but then we'd have to convert our functions to strings
- and then piece it back together later.
- There's less overhead this way.. */
- function __get ($x) {
- global $dot; // We'll define it later down the line
- return $dot ($this, $GLOBALS[trim($x)]);
- }
- }
- /* At this point we have partial application
- and function composition, however, we have
- to create functions like this:
- $const = new Funky ( function ($x) {
- return new Funky ( function ($y) use ($x) {
- return $x;
- });
- });
- Yuck! That's painfully verbose!
- Because the sole purpose of this library is to
- circumvent the verbosity of PHP, we are not going
- to settle for this! We'll create a small DSL that
- transpiles to that mess!
- */
- // Usage: $add3 = func_ (x,y,z) ['return $x + $y + $z;'] (global, variables);
- function func_ (...$args) {
- return new Funky ( function ($body) use ($args) {
- return function (...$globals) use ($args, $body) {
- $args = array_map (function ($x) { return "\$$x"; }, $args);
- $globals = array_map (function ($x) { return "\$$x"; }, $globals);
- $ret = "";
- $tail = "";
- $first = true;
- foreach ($args as $a) {
- if (!$first) $ret .= "return ";
- $ret .= "new Funky(function ($a) ";
- if (count($globals) != 0) $ret .= "use (" . implode (', ', $globals) . ") ";
- $ret .= "{ ";
- $tail .= " });";
- $globals[] = $a;
- $first = false;
- }
- return $ret . $body . $tail;
- };
- });
- }
- function func (...$args) {
- return new Funky ( function ($body) use ($args) {
- return function (...$globals) use ($args, $body) {
- $code = call_user_func_array(call_user_func_array ('func_', $args) [$body], $globals);
- //echo $code, "\n\n";
- return eval ("return $code");
- };
- });
- }
- // And because that's also too long for my liking:
- // € (x,y) ['return $x + $y'];
- function € (...$args) {
- return new Funky ( function ($body) use ($args) {
- return call_user_func_array ('func', $args) [$body] ();
- });
- }
- // Better still: £ (x,y) ['$x + $y'];
- function £ (...$args) {
- return new Funky ( function ($body) use ($args) {
- return call_user_func_array ('func', $args) ["return $body; "] ();
- });
- }
- // Short with globals: § (x,y) ['$x + $y + $z'] (z);
- function § (...$args) {
- return new Funky ( function ($body) use ($args) {
- return function (...$gs) use ($args,$body) {
- $gs = array_map (function ($x) { return "\$$x"; }, $gs);
- return call_user_func_array('func', $args) ["global ".implode(',', $gs)."; return $body; "] ();
- };
- });
- }
- /* Usage:
- $add = £ (x,y ) ['$x + $y'];
- $add3 = £ (x,y,z) ['$x + $y + $z'];
- Syntax rules:
- * You cannot use two parentaces directly after each other:
- $add (1, 2) // 3
- $add [1] [2] // 3
- $add (1) [2] // 3
- $add (1) (2) // Syntax error
- $add3 (1,1,1) // 3
- $add3 (1) [1] (1) // 3
- $add3 (1,1) [1] // 3
- * You cannot use parentaces directly after function composition (that sucks!):
- $add (1) -> add [1] (1) // 3
- $add (1) -> add (1) [1] // Syntax error
- $add (1) -> add (1, 1) // Syntax error
- $add [1] -> add [1] -> add3 [1] (1, 1) // 5
- */
- /* ===== Useful functions ===== */
- $id = £ (x) ['$x']; // $id [1] == 1
- $const = £ (x,_) ['$x']; // $const [1] [2] == 1
- $dot = £ (f,a,x) ['$f [$a[$x]]']; // $dot ($fa, $fb, $x) == $fa -> fb [$x] == $fa [$fb [$x]]
- $flip = £ (f,x,y) ['$f ($y, $x)']; // $flip [$const] (1, 2) == 2
- $ap = £ (f,g,x) ['$f [$x] [$g [$x]]'];
- /* ==== Boolean logic ==== */
- // We can implement boolean logic with functions
- $not = $flip;
- $yes = $const;
- $no = $not [$yes];
- $or = $ap ($id, $id);
- $and = § (x,y) ['$not [$or ($not [$x], $not [$y])]'] (not,'or');
- // Convert a funky boolean to a PHP one
- $is = £ (c) ['$c (true, false)'];
- /* ==== Numbers ==== */
- // A number is literally to run some function n times over some value
- $zero = $flip [$const];
- $isZero = § (n) ['$n ($yes [$no], $yes)'] (yes,no); // TODO
- $mult = $dot;
- $succ = $ap [$dot];
- $pow = $flip [$id];
- $add = £ (n,m,f,z) ['$n ($f, $m ($f, $z))'];
- // pred has always been difficult- I recommend not reading it ..
- $pred=§(n,f,z)['(($n['.substr(func_(g,h)['return$h[$g[$f]];'](f),0,-1).'])[$const[$z]])[$id]']('const',id);
- // Fortunatly subtracting is fairly straight when you have pred ..
- $sub = § (m,n) ['$n ($pred, $m)'] (pred);
- // Convert a funky number to a PHP one
- $num = new Funky ( function ($n) {
- return $n [new Funky ( function ($x) {
- return $x + 1;
- })] [0];
- });
- // Some numbers for convenience (and sanity check)
- $one = $succ [$zero];
- $two = $succ [$one ];
- $three = $succ -> succ -> succ [$zero];
- $four = $pow [$two] [$two];
- $five = $add ($two, $three);
- $six = $mult ($two, $three);
- /* ==== Equality ==== */
- $leq = § (m,n) ['$isZero [$sub ($m, $n)]'] (isZero,sub);
- $gt = § (x ) ['$dot [$not] [$leq ($x)]'] (dot,leq,'not');
- $eq = § (m,n) ['($leq ($m, $n)) ($leq ($n, $m)) [$no]'] (leq,no);
- ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement