introduce dropWhile function + test
authorwidmogrod <widmogrod@gmail.com>
Sun, 11 Feb 2018 00:44:57 +0000 (01:44 +0100)
committerwidmogrod <widmogrod@gmail.com>
Sun, 18 Feb 2018 17:47:11 +0000 (18:47 +0100)
src/Functional/sublist.php
test/Functional/DropWhileTest.php [new file with mode: 0644]

index 9262277..5ecaf64 100644 (file)
@@ -6,6 +6,8 @@ namespace Widmogrod\Functional;
 
 use Widmogrod\Primitive\EmptyListError;
 use Widmogrod\Primitive\Listt;
+use Widmogrod\Primitive\ListtCons;
+use Widmogrod\Primitive\ListtNil;
 
 /**
  * @var callable
@@ -65,6 +67,47 @@ function drop(int $n, Listt $xs = null)
 /**
  * @var callable
  */
+const dropWhile = 'Widmogrod\Functional\dropWhile';
+
+/**
+ *
+ * dropWhile :: (a -> Bool) -> [a] -> [a]
+ *
+ * ```haskell
+ * dropWhile _ []          =  []
+ * dropWhile p xs@(x:xs')
+ *  | p x       =  dropWhile p xs'
+ *  | otherwise =  xs
+ * ```
+ *
+ * @param callable $predicate
+ * @param Listt $xs
+ * @return Listt
+ */
+function dropWhile(callable $predicate, Listt $xs = null)
+{
+    return curryN(2, function (callable $predicate, Listt $xs): Listt {
+        if ($xs instanceof ListtNil) {
+            return $xs;
+        }
+
+        $tail = $xs;
+        do {
+            $x = head($tail);
+            if (!$predicate($x)) {
+                return $tail;
+            }
+
+            $tail = tail($tail);
+        } while ($tail instanceof ListtCons);
+
+        return fromNil();
+    })(...func_get_args());
+}
+
+/**
+ * @var callable
+ */
 const span = 'Widmogrod\Functional\span';
 
 /**
diff --git a/test/Functional/DropWhileTest.php b/test/Functional/DropWhileTest.php
new file mode 100644 (file)
index 0000000..8b7471e
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+namespace test\Functional;
+
+use Widmogrod\Primitive\Listt;
+use function Widmogrod\Functional\dropWhile;
+use function Widmogrod\Functional\fromIterable;
+use function Widmogrod\Functional\fromNil;
+use function Widmogrod\Functional\lt;
+
+class DropWhileTest extends \PHPUnit\Framework\TestCase
+{
+    /**
+     * @dataProvider provideData
+     */
+    public function test_it(
+        Listt $a,
+        callable $fn,
+        Listt $expected
+    ) {
+        $result = dropWhile($fn, $a);
+
+        $r = print_r($result->extract(), true);
+        $e = print_r($expected->extract(), true);
+
+        $this->assertTrue(
+            $result->equals($expected),
+            "$e != $r"
+        );
+    }
+
+    public function provideData()
+    {
+        return [
+            'should return empty list from when input is empty list' => [
+                '$a' => fromNil(),
+                '$fn' => lt(3),
+                '$expected' => fromNil(),
+            ],
+            'should provided list when < 100' => [
+                '$a' => fromIterable([1, 2, 3, 4, 5]),
+                '$fn' => lt(100),
+                '$expected' => fromIterable([]),
+            ],
+            'should return part of finite list' => [
+                '$a' => fromIterable([1, 2, 3, 4, 5]),
+                '$fn' => lt(4),
+                '$expected' => fromIterable([4, 5]),
+            ],
+            'should return nil list when drop more than in the list' => [
+                '$a' => fromIterable([1, 2, 3, 4, 5]),
+                '$fn' => lt(400),
+                '$expected' => fromNil(),
+            ],
+        ];
+    }
+}