Advertisement
Guest User

Untitled

a guest
Aug 25th, 2016
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 6.95 KB | None | 0 0
  1. <?php error_reporting(E_ALL & ~E_NOTICE);
  2.  
  3.   /* ===== funky.php =====
  4.      PHP is painfully verbose. This library is an
  5.      attempt at combating that verbosity by introducing
  6.      functional concepts.
  7.  
  8.      This library aims to be self documenting, and is
  9.      best understood by reading it top to bottom with
  10.      this file loaded in a interactive interpreter.
  11.   */
  12.  
  13.  
  14.   /* Unlike most other languages, this is a syntax error in PHP:
  15.         $f (1) (2);
  16.      However, this is perfectly valid:
  17.         $k = $f (1); $k (2);
  18.      Fortunatly, you are allowed to fetch something from a 2D array like this:
  19.         $arr [1] [2];
  20.      So let's exploit that!
  21.   */
  22.   class Funky implements ArrayAccess {
  23.     private $f;
  24.     function __construct ($f) { $this->f = $f; }
  25.  
  26.     // called when you do: f [x]
  27.     function offsetGet ($x) {
  28.         $f = $this->f; // Mandatory unboxing boilerplate
  29.         return $f($x);
  30.     }
  31.  
  32.     // Absolutely 100% required boilerplate code
  33.     function offsetExists ($a) {}
  34.     function offsetSet ($a,$b) {}
  35.     function offsetUnset ($a)  {}
  36.  
  37.  
  38.     // Allows you to call our class like a regular function to
  39.     // pass it multiple valus: f (1, 2) [3]
  40.     function __invoke (...$args) {
  41.       $f = $this;
  42.       foreach ($args as $x) $f = $f [$x];
  43.       return $f;
  44.     }
  45.  
  46.  
  47.     /* Allows you to do function composition like this:
  48.           add [2] -> add [3]
  49.        We could technically get to use dots for function
  50.        composition by overriding the toString function,
  51.        but then we'd have to convert our functions to strings
  52.        and then piece it back together later.
  53.  
  54.        There's less overhead this way.. */
  55.     function __get ($x) {
  56.       global $dot; // We'll define it later down the line
  57.       return $dot ($this, $GLOBALS[trim($x)]);
  58.     }
  59.   }
  60.  
  61.  
  62.   /* At this point we have partial application
  63.      and function composition, however, we have
  64.      to create functions like this:
  65.          $const = new Funky ( function ($x) {
  66.              return new Funky ( function ($y) use ($x) {
  67.                  return $x;
  68.              });
  69.          });
  70.  
  71.       Yuck! That's painfully verbose!
  72.       Because the sole purpose of this library is to
  73.       circumvent the verbosity of PHP, we are not going
  74.       to settle for this! We'll create a small DSL that
  75.       transpiles to that mess!
  76.   */
  77.  
  78.   // Usage: $add3 = func_ (x,y,z) ['return $x + $y + $z;'] (global, variables);
  79.   function func_ (...$args) {
  80.     return new Funky ( function ($body) use ($args) {
  81.       return function (...$globals) use ($args, $body) {
  82.         $args    = array_map (function ($x) { return "\$$x"; }, $args);
  83.         $globals = array_map (function ($x) { return "\$$x"; }, $globals);
  84.         $ret     = "";
  85.         $tail    = "";
  86.         $first   = true;
  87.  
  88.         foreach ($args as $a) {
  89.           if (!$first) $ret .= "return ";
  90.           $ret  .= "new Funky(function ($a) ";
  91.           if (count($globals) != 0) $ret .= "use (" . implode (', ', $globals) . ") ";
  92.           $ret  .= "{ ";
  93.           $tail .= " });";
  94.  
  95.           $globals[] = $a;
  96.           $first     = false;
  97.         }
  98.  
  99.         return $ret . $body . $tail;
  100.       };
  101.     });
  102.   }
  103.   function func  (...$args) {
  104.     return new Funky ( function ($body) use ($args) {
  105.       return function (...$globals) use ($args, $body) {
  106.         $code = call_user_func_array(call_user_func_array ('func_', $args) [$body], $globals);
  107.         //echo $code, "\n\n";
  108.         return eval ("return $code");
  109.       };
  110.     });
  111.   }
  112.  
  113.   // And because that's also too long for my liking:
  114.   //    € (x,y) ['return $x + $y'];
  115.   function(...$args) {
  116.     return new Funky ( function ($body) use ($args) {
  117.       return call_user_func_array ('func', $args) [$body] ();
  118.     });
  119.   }
  120.  
  121.   // Better still: £ (x,y) ['$x + $y'];
  122.   function £ (...$args) {
  123.     return new Funky ( function ($body) use ($args) {
  124.       return call_user_func_array ('func', $args) ["return $body; "] ();
  125.     });
  126.   }
  127.  
  128.   // Short with globals: § (x,y) ['$x + $y + $z'] (z);
  129.   function § (...$args) {
  130.     return new Funky ( function ($body) use ($args) {
  131.       return function (...$gs) use ($args,$body) {
  132.         $gs = array_map (function ($x) { return "\$$x"; }, $gs);
  133.         return call_user_func_array('func', $args) ["global ".implode(',', $gs)."; return $body; "] ();
  134.       };
  135.     });
  136.   }
  137.  
  138.   /* Usage:
  139.         $add  = £ (x,y  ) ['$x + $y'];
  140.         $add3 = £ (x,y,z) ['$x + $y + $z'];
  141.  
  142.      Syntax rules:
  143.       * You cannot use two parentaces directly after each other:
  144.           $add (1, 2)  // 3
  145.           $add [1] [2] // 3
  146.           $add (1) [2] // 3
  147.           $add (1) (2) // Syntax error
  148.  
  149.           $add3 (1,1,1)     // 3
  150.           $add3 (1) [1] (1) // 3
  151.           $add3 (1,1) [1]   // 3
  152.  
  153.       * You cannot use parentaces directly after function composition (that sucks!):
  154.           $add (1) -> add [1] (1) // 3
  155.           $add (1) -> add (1) [1] // Syntax error
  156.           $add (1) -> add (1, 1)  // Syntax error
  157.           $add [1] -> add [1] -> add3 [1] (1, 1) // 5
  158.   */
  159.  
  160.  
  161.   /* ===== Useful functions ===== */
  162.   $id    = £ (x)     ['$x']; // $id [1] == 1
  163.   $const = £ (x,_)   ['$x']; // $const [1] [2] == 1
  164.   $dot   = £ (f,a,x) ['$f [$a[$x]]']; // $dot ($fa, $fb, $x) == $fa -> fb [$x] == $fa [$fb [$x]]
  165.   $flip  = £ (f,x,y) ['$f ($y, $x)']; // $flip [$const] (1, 2) == 2
  166.   $ap    = £ (f,g,x) ['$f [$x] [$g [$x]]'];
  167.  
  168.  
  169.   /* ==== Boolean logic ==== */
  170.   // We can implement boolean logic with functions
  171.  
  172.   $not = $flip;
  173.   $yes = $const;
  174.   $no  = $not [$yes];
  175.   $or  = $ap ($id, $id);
  176.   $and = § (x,y) ['$not [$or ($not [$x], $not [$y])]'] (not,'or');
  177.  
  178.   // Convert a funky boolean to a PHP one
  179.   $is  = £ (c) ['$c (true, false)'];
  180.  
  181.   /* ==== Numbers ==== */
  182.   // A number is literally to run some function n times over some value
  183.  
  184.   $zero   = $flip [$const];
  185.   $isZero = § (n) ['$n ($yes [$no], $yes)'] (yes,no); // TODO
  186.  
  187.   $mult = $dot;
  188.   $succ = $ap [$dot];
  189.   $pow  = $flip [$id];
  190.  
  191.   $add  = £ (n,m,f,z) ['$n ($f, $m ($f, $z))'];
  192.  
  193.   // pred has always been difficult- I recommend not reading it ..
  194.   $pred=§(n,f,z)['(($n['.substr(func_(g,h)['return$h[$g[$f]];'](f),0,-1).'])[$const[$z]])[$id]']('const',id);
  195.  
  196.   // Fortunatly subtracting is fairly straight when you have pred ..
  197.   $sub = § (m,n) ['$n ($pred, $m)'] (pred);
  198.  
  199.   // Convert a funky number to a PHP one
  200.   $num = new Funky ( function ($n) {
  201.       return $n [new Funky ( function ($x) {
  202.           return $x + 1;
  203.       })] [0];
  204.   });
  205.  
  206.   // Some numbers for convenience (and sanity check)
  207.   $one   = $succ [$zero];
  208.   $two   = $succ [$one ];
  209.   $three = $succ -> succ -> succ [$zero];
  210.   $four  = $pow [$two] [$two];
  211.   $five  = $add ($two, $three);
  212.   $six   = $mult ($two, $three);
  213.  
  214.   /* ==== Equality ==== */
  215.   $leq = § (m,n) ['$isZero [$sub ($m, $n)]'] (isZero,sub);
  216.   $gt  = § (x  ) ['$dot [$not] [$leq ($x)]'] (dot,leq,'not');
  217.   $eq  = § (m,n) ['($leq ($m, $n)) ($leq ($n, $m)) [$no]'] (leq,no);
  218.  
  219. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement