Functional\zip make to work on infinite lists
authorwidmogrod <widmogrod@gmail.com>
Thu, 21 Dec 2017 17:28:23 +0000 (18:28 +0100)
committerwidmogrod <widmogrod@gmail.com>
Thu, 21 Dec 2017 17:28:23 +0000 (18:28 +0100)
src/Functional/listt.php
src/Functional/zipping.php
test/Functional/ZipTest.php

index 76becbd..8aae889 100644 (file)
@@ -141,7 +141,9 @@ const prepend = 'Widmogrod\Functional\prepend';
 function prepend($x, Listt $xs = null)
 {
     return curryN(2, function ($x, Listt $xs): Listt {
-        return append(fromValue($x), $xs);
+        return ListtCons::of(function () use ($x, $xs) {
+            return [$x, $xs];
+        });
     })(...func_get_args());
 }
 
index fdb567d..4c70528 100644 (file)
@@ -4,6 +4,7 @@ namespace Widmogrod\Functional;
 
 use Widmogrod\Primitive\EmptyListError;
 use Widmogrod\Primitive\Listt;
+use Widmogrod\Primitive\ListtCons;
 
 /**
  * @var callable
@@ -16,23 +17,23 @@ const zip = 'Widmogrod\Functional\zip';
  * zip takes two lists and returns a list of corresponding pairs. If one input list is short, excess elements of the longer list are discarded.
  * zip is right-lazy:
  *
- * @param Listt $a
- * @param Listt|null $b
+ * @param Listt $xs
+ * @param Listt|null $ys
  * @return Listt
  */
-function zip(Listt $a, Listt $b = null)
+function zip(Listt $xs, Listt $ys = null)
 {
-    return curryN(2, function (Listt $a, Listt $b): Listt {
+    return curryN(2, function (Listt $xs, Listt $ys): Listt {
         try {
-            $x = head($a);
-            $y = head($b);
-            $xs = tail($a);
-            $ys = tail($b);
+            $x = head($xs);
+            $y = head($ys);
 
-            return prepend(
-                [$x, $y],
-                zip($xs, $ys)
-            );
+            return ListtCons::of(function () use ($x, $y, $xs, $ys) {
+                return [
+                    [$x, $y],
+                    zip(tail($xs), tail($ys))
+                ];
+            });
         } catch (EmptyListError $e) {
             return fromNil();
         }
index 103dcc8..1ddf55a 100644 (file)
@@ -2,13 +2,22 @@
 
 namespace test\Functional;
 
-use function Widmogrod\Functional\fromNil;
+use Eris\Generator;
+use Eris\TestTrait;
 use Widmogrod\Primitive\Listt;
+use function Widmogrod\Functional\eql;
+use function Widmogrod\Functional\filter;
 use function Widmogrod\Functional\fromIterable;
+use function Widmogrod\Functional\fromNil;
+use function Widmogrod\Functional\length;
+use function Widmogrod\Functional\repeat;
+use function Widmogrod\Functional\take;
 use function Widmogrod\Functional\zip;
 
 class ZipTest extends \PHPUnit_Framework_TestCase
 {
+    use TestTrait;
+
     /**
      * @dataProvider provideData
      */
@@ -66,4 +75,17 @@ class ZipTest extends \PHPUnit_Framework_TestCase
             ]
         ];
     }
+
+    public function test_it_should_work_on_infinite_lists()
+    {
+        $this->forAll(
+            Generator\choose(1, 100),
+            Generator\string(),
+            Generator\string()
+        )->then(function ($n, $a, $b) {
+            $list = take($n, zip(repeat($a), repeat($b)));
+
+            return length(filter(eql([$a, $b]), $list)) === $n;
+        });
+    }
 }