{"id":13593186,"url":"https://github.com/kapolos/pramda","last_synced_at":"2026-01-14T00:53:19.577Z","repository":{"id":57004428,"uuid":"48879610","full_name":"kapolos/pramda","owner":"kapolos","description":"Practical Functional Programming in PHP","archived":false,"fork":false,"pushed_at":"2018-06-10T14:50:55.000Z","size":47,"stargazers_count":244,"open_issues_count":6,"forks_count":13,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-11-07T05:24:59.733Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kapolos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-01T14:06:49.000Z","updated_at":"2025-03-21T13:38:56.000Z","dependencies_parsed_at":"2022-08-21T12:10:50.934Z","dependency_job_id":null,"html_url":"https://github.com/kapolos/pramda","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kapolos/pramda","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kapolos%2Fpramda","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kapolos%2Fpramda/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kapolos%2Fpramda/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kapolos%2Fpramda/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kapolos","download_url":"https://codeload.github.com/kapolos/pramda/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kapolos%2Fpramda/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28407466,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T00:40:43.272Z","status":"ssl_error","status_checked_at":"2026-01-14T00:40:42.636Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T16:01:17.429Z","updated_at":"2026-01-14T00:53:19.548Z","avatar_url":"https://github.com/kapolos.png","language":"PHP","funding_links":[],"categories":["PHP","Libraries"],"sub_categories":["[PHP](https://github.com/php/php-src)"],"readme":"# Pramda\n\n### Practical Functional Programming in PHP\n#### P.S. 1: Automatically Curried Functions\n#### P.S. 2: Lazy Evaluation baked-in\n#### P.S. 3: Fun(ctional) to Use\n\n---\n\n### ELI5: What is Functional Programming and Why Do I Care?\n\nIs it possible that something you're working on could be done in a different way? Turns out that yes it can, and it can be done in multiple ways - or \"paradigms\" if you prefer a fancier term. One such paradigm is Functional Programming.\n\nNow, if you go and read Haskell's [Functional Programming](https://wiki.haskell.org/Functional_programming) Wiki page, you might get the impression that it's some really complex, weird, unnecessary convoluted ... \"thing\". That's just because texts about Functional Programming - even introductory ones - are usually written in a dry \"academic\" way with which most PHP programmers are not accustomed with. In reality though, Functional Programming is about things you already do and espouse in your daily practice, taken to the maximum.\n\nFor example, you most probably have been using Composer. The idea behind package managers such as Composer, is that you create stand-alone pieces of work that you can then (at will) compose into something bigger. Well, **congratulations**, that's exactly what Functional Programming is about - but instead of working with \"packages\", you work with functions. Explained like that, it makes perfect sense. If you understand the benefits of composing packages, you understand the benefits of working with composable functions.\n\nJust as you have to follow some conventions when creating and utilizing a Composer package, you need to follow some conventions when working with functions. The good news is that it's as easy as riding a bicycle. Do you remember how hard it was the first few times? And how it became second nature shortly after? It's the same thing with Functional Programming if you manage to stick with it after the first few falls. At first, things will seem unnatural compared to the way you're used to. Later on, you'll come to realize that just like the bike, Functional Programming can be efficient and fun. And just like you know that using a bicycle is not always the best choice for every situation, you'll know when to pick Functional Programming from your toolbox to sculpt your masterpiece.\n\n#### Show me a code example if you want me to read the wall of text below\n\nTask: \n\n\u003e From a text file, determine the n most frequently used words, and print out a sorted list of those words along with their frequencies.\n\nImplementation:\n\n```php\n$text = P::file('textfile.txt'); // Lazy read line by line with generators\n\n$onlyWords = function ($txt) {\n    return preg_split(\"/[^A-Za-z]/\", $txt, NULL, PREG_SPLIT_NO_EMPTY);\n};\n\n// Here we go... composing simple functions into what we need\n$wordsPerLine = P::map(P::compose($onlyWords, P::unary('strtolower')));\n$getFreq = P::countBy('P::identity');\n$sortDesc = P::sort('P::negate');\n$getWordsFrequencyDesc = P::compose(\n    $sortDesc,\n    $getFreq,\n    'P::flatten',\n    $wordsPerLine\n);\n$topFiveFreq = P::compose('P::toArray', P::take(5), $getWordsFrequencyDesc); // Just the top 5, for fun\n$printEm = P::each(function($value, $key) {\n   echo $key . \": \" . $value . \"\\n\";\n});\n\n// And now, we apply to the data\n$results = $printEm($topFiveFreq($text));\n```\n\nThis uses lazy evaluation behind the scenes - which in general only requires a thin boilerplate over an eager implementation (usually `P::map` , `P::flatten` \u0026 `P::toArray`). \n\nOn a quick test using _Alice in Wonderland_ (3700 lines) as input, `memory_get_peak_usage` was at **1 MB** vs the nearly **6 MB** of the eager version. Not bad and no need to manually use generators to reap the benefits.\n\n##### Note\n\nThat weird `P::unary` that wraps `strtolower`? That's because `P::map` always calls the supplied function with 2 parameters (value, key). Native PHP functions that expect 1 parameter do not ignore the extra parameter, so we need to wrap them inside a closure and pass only 1 parameter to them. `P::unary` takes a function and any number of parameters and passes only the first one to it.\n\n## Understanding Functional Programming for Fun and Profit\n\nWe are going to do a down-to-earth roundup of functional programming concepts. Pramda exists so that it makes it easy to utilize all these concepts without the verbosity and boilerplate cost. But you still need to have the understanding of what's going on.\n\n### Composition\n\nIf `(gof)(x) = g(f(x))` means something more to you other than ASCII IRC art, you were paying attention to your math teacher at school. You don't need to know about composition in Mathematical terms to do Functional Programming. Just keep in mind that what you'll read below is succinctly expressed by the above relation.\n\nSuppose we have:\n````php\nfunction getTweets($username) {\n\t// returns array of tweets\n}\nfunction sortByDateAsc($list) {\n\t// returns sorted array\n}\n````\n\nThen we could do:\n\n```php\n$myTweets = getTweets('kapolos');\n$mySortedTweets = sortByDateAsc($myTweets);\n```\n\nOr we could have done:\n\n```php\n$mySortedTweets = sortByDateAsc(getTweets('kapolos'));\n```\n\nWhat we wouldn't have done is:\n\n```php\n// Function that generates a function that gets and sorts tweets\n$sortedTweetsWrapper = function() {\n\treturn function($username) {\n\t\treturn sortByDateAsc(getTweets($username));\n\t};\n};\n$getSortedTweets = $sortedTweetsWrapper();\n\n$mySortedTweets = $getSortedTweets('kapolos');\n```\n\nApart from being an eye-sore, the difference that we care about is that in this snippet `$getSortedTweets` is a function that we created by calling some weird \"wrapper\" function. `$getSortedTweets` is a function that does the exact same thing as `sortByDateAsc(getTweets($username))` (which is not a function, but a series of \"steps\").\n\nOk, so what?\n\nSince it's a function, we can make it more generic:\n\n```php\n// Function that generates a function based on two other functions for our example\n$compose = function($sort, $fetch) {\n\treturn function($username) use ($sort, $fetch) {\n\t\treturn $sort($fetch($username));\n\t};\n};\n$getSortedTweets = $compose('sortByDateAsc', 'getTweets');\n\n$mySortedTweets = $getSortedTweets('kapolos');\n```\n\nIt still does the same thing, only now we can pass the fetching and sorting functions as parameters. And all this juggling was done exactly for this reason. To have a function to which we can pass other functions and it will make for us a new function which we can use later on.\n\nIn other words, we just described the way in which we are going to be plugging functions together . Doing it this way (creating a function that returns a new function) will allow us to do the cool things later on.\n\nWith Pramda:\n\n```php\n$getSortedTweets = P::compose('sortByDateAsc', 'getTweets');\n$mySortedTweets = $getSortedTweets('kapolos');\n```\n\nNotice how the order of execution in composition is from right to left. `P::pipe` can be used instead for left-to-right composition if you prefer it that way.\n\n### Mapping yes, iterations no\n\nTime to forget `for`, `foreach`, `while` and all the other gazillion ways to loop through a list. Instead you will be using `map`, `reduce` and friends.\n\nWhenever you have an array, you will mentally disregard the ability to iterate over its items one by one. Instead, you should be thinking - \"_what function can I apply over this set of values to give me a new set that will be like X_\"? Yes, the function will still be applying the transformation to each item individually.\n\nInstead of:\n```php\n$before = [1,2,3,4,5];\n$after = [];\nforeach ($before as $num) {\n\t$after[] = $num * 2;\n}\n```\n\nyou will be doing:\n\n```php\n$before = [1,2,3,4,5];\n$after = P::map(function($num) {\n\treturn $num * 2;\n}, $before);\n/* P::toArray($after) //=\u003e [2,4,6,8,10] */\n```\n\nor \n\n```php\n$before = [1,2,3,4,5];\n$doubleNum = function($num) {\n\treturn $num * 2;\n};\n$doubleAllNumbers = P::map($doubleNum); // Auto-currying ftw (see later on)\n$after = $doubleAllNumbers($before);\n/* P::toArray($after) //=\u003e [2,4,6,8,10] */\n```\n\nSo again - why? The answer is (once more) the same. By avoiding direct iteration we will be using functions which, as we saw above, we can compose. Sweet!\n\nNote: Not all iterations can be replaced by `map/reduce` but all can be replaced by recursion. While PHP does not support tail recursion and blows its stack at a depth of 100\u003csup\u003e1\u003c/sup\u003e, we can use the trampoline technique to avoid using the stack for each invocation. Pramda includes a `trampoline` function to help you do that.\n\n\u003csup\u003e1\u003c/sup\u003e: 100 with XDebug enabled, otherwise the exact number depends - the [manual](https://secure.php.net/manual/en/functions.user-defined.php) advises against doing \"100-200 recursion levels\".\n\n### Currying\n\nCurrying is cool. Automatic currying is super cool. But what ... is it?\n\nConsider this simple function:\n```php\n$add = function ($a, $b) {\n\treturn $a + $b;\n};\n```\n\nIf we want to create a function that increases its argument by 1 using the `add` function above, we would do something like:\n```php\n$inc = function($value) use ($add){\n\treturn $add($value, 1);\n};\n/*\n $inc(2); //=\u003e 3\n*/\n```\n\nIf `add` was a curried function, we could have done this:\n```php\n$inc = $add(1);\n/*\n $inc(2); //=\u003e 3\n*/\n```\n\nIn other words, a curried function is able to execute step by step. In the example above, `$add(1)` is a new function that takes one argument. Once it is called, it applies both \"1\" and the latest passed value to the original `$add`  function.\n\n`P` functions are curried by default (unless it doesn't make sense to, or they are explicitly marked as non-curried).\n```php\n$inc = P::add(1); // P::add is an existing function\n```\n\nYou can also manually curry your closures. In our example, to get the curried version of `add` we would have:\n```php\n$add = function ($a, $b) {\n\treturn $a + $b;\n};\n$curriedAdd = P::curry2($add);\n$inc = $curriedAdd(1);\n$inc(2); //=\u003e 3\n```\n\nSimilarly for a function that takes 3 arguments:\n\n```php\n$add3 = function ($a, $b, $c) {\n    return $a + $b + $c;\n};\n$curriedAdd3 = P::curry3($add3);\n\n// One\n$add1 = $curriedAdd3(1);\n$add1(2,3); //=\u003e 6\n\n// Two\n$add1then2 = $curriedAdd3(1, 2);\n$add1then2(3); //=\u003e 6\n\n// Two again\n$add1then2 = $add1(2);\n$add1then2(3); //=\u003e 6\n```\n\nCurrying combined with composition is what makes Pramda elegant and fun to use.\n\n### Immutable data \u0026 no side effects\n\nTo avoid any surprises in your code, you need to keep in mind the following guidelines:\n\n* A function should not mutate data passed to it\n* A function should not modify variables outside of its scope\n\nIn other words, don't pass values by reference and don't use `global`.\n\nContrived example of big **no-no**:\n```php\n$counter = 3;\n$number = 2;\nfunction toTheEighth(\u0026$number) {\n\tglobal $counter;\n\t\n\twhile ($counter-- \u003e 0) {\n\t\t$number *= $number;\n\t}\n\t\n\treturn $number;\n}\n\n/*\ntoTheEighth($number) //=\u003e 256\n$number //=\u003e 256\n$counter //=\u003e 0\n*/\n```\n\n### Lazy evaluation\n\nWhen you need to load a small/medium size text file, you probably use `file`, which loads the whole text into an array. When you need to work with a huge file, this approach does not work and you use an alternative implementation with `fgets` to read the content of the file line by line, in order to avoid hitting the memory limit.\n\nLazy evaluation is about doing the same thing but with objects that implement the `Iterator` interface instead of IO.\n\nLazy evaluation:\n\n* only use the part of the list you need, when you need it. \n* only provide one item of the list each time another function asks for the list inside a loop\n\nPHP supports lazy evaluation via the `Generator` primitives since v5.5\n\nEager:\n```php\n$double = function($arr) {\n\t$out = [];\n\tforeach ($arr as $item) {\n\t\t$out[] = $item * 2;\n\t}\n\treturn $out;\n}\n// $double([1,2,3]); /=\u003e [2,4,6]\n```\n\nThe eager function will take a copy of the whole array before doing any work on it, then it will compute a new array and return that as the result.\n\nLazy:\n```php\n$double = function($arr) {\n\tforeach($arr as $item) {\n\t\tyield $item * 2;\n\t}\n};\n$list = $double([1,2,3]);\nforeach($list as $item) {\n\techo $item.' ';\n}\n//=\u003e 2 4 6\n```\n\nA lazy function takes only one item  from the array each time it needs to and yields (returns) the result as a value of a generator. Whenever (usually at the end of a long path of transformations) we need to use the actual values, we iterate over the generator and get the value of each item.\n\nThe great benefit of generators is lower memory usage. Since arrays are not copied on every function, less memory will be occupied.  Given that functional programing is all about passing immutable data to functions, lazy evaluation is a big win.\n \n\n## Pramda\n\n### What's in the name?\n\nI chose to call this library Pramda for 2 reasons:\n\n##### It's sounds like composition of Practical and Lambda\n \n\"Sounds\", because there's that pesky \"b\" between the \"m\" and the \"d\". Prambda just doesn't make the cut. Prabda is meh. Prbda is ... well that's just isn't going to make it either.\nInterestingly enough, the Greek word for the letter `λ` is `λάμδα` - no `b` in there.\n\n##### A tribute to Ramda.js\n\nPramda started as my desire to bring Ramda.js from the world of Javascript over to the PHP lands. Ramda.js has in my humble opinion taken a very balanced approach between practicality and purity/tradition that makes the library fun to use. \n\nNotable differences include:\n* Pramda supports lazy evaluation wherever possible. Efficiency and memory use are major concerns.\n* Pramda will not port/follow Fantasy-land spec.\n* Not a 1-to-1 port for 2 reasons. First, some things are Javascript-isms that have no place in a PHP library. Furthermore, some functions make better sense for PHP usage if implemented differently from Ramda.js.\n* Pramda's target audience has different needs that Ramda.js's audience. So development has to reflect that.\n\n### Usage\n\nYou get a `P` class in the global namespace. All functions are static, for example `P::add`.\n\n#### Via Composer\n\nAdd this to your `require` section:\n`\"kapolos/pramda\": \"0.9.*@dev\"`\n\n#### Manually\n\n`require ('src/pramda.php');`\n\n#### Compatibility\n\nTested on PHP **5.6**. I have avoided using `...args` so it should be working with **5.5** as well but I have not tested that (todo).\n\n#### Tests\n\nPramda uses the venerable PHPUnit for testing.\n\n```bash\n\n# vendor\\bin\\phpunit.bat --debug\nPHPUnit 4.8.21 by Sebastian Bergmann and contributors.\n\n................................................................ 64 / 79 ( 81%)\n...............\n\nTime: 557 ms, Memory: 3.75Mb\n\nOK (79 tests, 244 assertions)\n\n```\n\n### Examples\n\n```php\n$planets = [\n  [\n      \"name\" =\u003e \"Earth\",\n      \"order\" =\u003e 3,\n      \"has\" =\u003e [\"moon\", \"oreos\"],\n      \"contact\" =\u003e [\n          \"name\" =\u003e \"Bob Spongebob\",\n          \"email\" =\u003e \"bob@spongebob.earth\"\n      ]\n  ],\n  [\n      \"name\" =\u003e \"Mars\",\n      \"order\" =\u003e 4,\n      \"has\" =\u003e [\"aliens\", \"rover\"],\n      \"contact\" =\u003e [\n          \"name\" =\u003e \"Marvin Martian\",\n          \"email\" =\u003e \"marvin@the.mars\"\n      ]\n  ],\n  [\n      \"name\" =\u003e \"Venus\",\n      \"order\" =\u003e 2,\n      \"has\" =\u003e [\"golden apple\"], // https://en.wikipedia.org/wiki/Golden_apple#The_Judgement_of_Paris\n      \"contact\" =\u003e [\n          \"name\" =\u003e \"Aphro Dite\",\n          \"email\" =\u003e \"aphrodite@gods.venus\"\n      ]\n  ],\n  [\n      \"name\" =\u003e \"Mercury\",\n      \"order\" =\u003e 1,\n      \"has\" =\u003e [],\n      \"contact\" =\u003e [\n          \"name\" =\u003e \"Buzz Off\",\n          \"email\" =\u003e \"no-reply@flames.mercury\"\n      ]\n  ],\n];\n```\n\n\u003e Who are the contacts?\n\n```php\n// Functions\n$nameOfContact = P::compose(P::prop('name'), P::prop('contact'));\n$getContactNames = P::map($nameOfContact);\n\n// Application\n$contacts = $getContactNames($planets); // Returns a generator\nP::toArray($contacts); //=\u003e [\"Bob Spongebob\", \"Marvin Martian\", \"Aphro Dite\", \"Buzz Off\"]\n```\n\n\u003e Who are the contacts, based on the planet's order from smallest to biggest?\n\n```php\n// Functions (cont'd)\n$sortByOrderAsc = P::sort(P::prop('order'));  // Returns an array (sort is eager)\n\n// Application\n$contacts = $getContactNames($sortByOrderAsc($planets)); // Returns a generator\nP::toArray($contacts)); //=\u003e [\"Buzz Off\", \"Aphro Dite\", \"Bob Spongebob\", \"Marvin Martian\"]\n```\n\n\u003e Who are the contacts in reverse alphabetical order?\n\n```php\n// Function (cont'd)\n$alphaDesc = P::compose('P::negate', 'ord');\n$sortByAlphaDesc = P::sort($alphaDesc);\n\n// Application\n$contacts = P::apply(P::compose($sortByAlphaDesc, $getContactNames), [$planets]);\n// or equivalently\n$contacts = P::apply(P::compose($sortByAlphaDesc, $getContactNames), P::of($planets));\n// or equivalently\n$contacts = $sortByAlphaDesc($getContactNames($planets));\n\n//=\u003e [\"Marvin Martian\", \"Bob Spongebob\", \"Buzz Off\", \"Aphro Dite\"]\n```\n\n\u003e But wait, I meant order by their surnames only, not the full names\n\n```php\n// Functions (cont'd)\n$lastname = P::compose('P::takeLast', P::split(' '));\n$lastnameAlphaDesc = P::compose($alphaDesc, $lastname);\n$sortByLastnameAlphaDesc = P::sort($lastnameAlphaDesc);\n\n// Application\n$contacts = $sortByLastnameAlphaDesc($getContactNames($planets));\n//=\u003e [\"Bob Spongebob\", \"Buzz Off\", \"Marvin Martian\", \"Aphro Dite\"]\n```\n\n\u003e Is Elvis somewhere in the Solar system?\n\n```php\n$hasElvis = P::compose(P::contains('Elvis'), P::prop('has'));\nP::contains(TRUE, P::map($hasElvis, $planets)); //=\u003e false\n```\n\n### Function List\n\nProper documentation is coming up next. For now, please see the list below and the doc blocks in the source code.\nAlso, you can see examples how to use each function in the unit tests.\n\n**Legend**:\n* `Yes` Explicitly supported\n* `No` Explicitly unsupported\n* `-` The combination may not make much sense or some other reason. For example, `converge` deals with closures alone and so data evaluation doesn't come into play.\n* `Kinda` You should read the associated note.\n\n| Name | Is Lazy | Supports Generators as Input | Curried |\n:------------: | :-------------: | :-------------: | :-------------: |\n| add | - | - | Yes |\n| all | Yes | Yes | Yes |\n| allPass | Yes | Yes | Yes |\n| add | - | - | Yes |\n| append | Yes | Yes | Yes\n| appendTo | Yes | Yes | Yes\n| apply | No | Yes | Yes\n| chain | Yes | Yes | Yes\n| compose | No | - | -\n| concat | Yes | Yes | Yes\n| converge | - | Yes | No\n| countBy \u003csup\u003e1\u003csup\u003e | Kinda | Yes | Yes\n| curry2 | - | - | -\n| curry3 | - | - | -\n| curryN | - | - | No\n| dec | - | - | No\n| divide | - | - | Yes\n| each | Yes | Yes | Yes\n| eq | - | - | Yes\n| eqBy | - | - | Yes\n| file | Yes | - | -\n| filter | Yes | Yes | Yes\n| flatten | Yes | Yes | -\n| flip \u003csup\u003e2\u003csup\u003e | - | - | No\n| gt | - | - | Yes\n| gte | - | - | Yes\n| head | - | Yes | -\n| identity | - | Yes | -\n| inc | - | - | -\n| join | Yes | Yes | Yes\n| last | Yes | Yes | -\n| lt | - | - | Yes\n| lte | - | - | Yes\n| map | Yes | Yes | Yes \n| mathMod | - | - | Yes\n| max | Yes | Yes | Yes\n| maxBy | Yes | Yes | Yes\n| merge | No | Yes | Yes\n| mergeAll | No | Yes | No\n| min | Yes | Yes | Yes\n| minBy | Yes | Yes | Yes\n| modulo | - | - | Yes\n| multiply | - | - | Yes\n| nd | - | - | Yes\n| negate | - | - | Yes\n| nth | Yes | Yes | Yes\n| of | - | - | -\n| partition | No | Yes | Yes\n| pipe | - | Yes | Yes\n| pluck | Yes | Yes | Yes\n| prepend | Yes | Yes | Yes\n| prependTo | Yes | Yes | Yes\n| product | Yes | Yes | Yes\n| prop | - | No | Yes\n| propOf | - | No | Yes\n| propOr | - | No | Yes\n| props \u003csup\u003e3\u003csup\u003e | No | No | Yes\n| reduce | - | Yes | Yes\n| reverse | No | Yes | -\n| set | - | No | Yes\n| size | - | Yes | -\n| slice | No | Yes | Yes\n| sort \u003csup\u003e4\u003csup\u003e | No | Yes | Yes\n| split | - | - | Yes\n| subtract | - | - | Yes\n| sum | - | Yes | Yes\n| tail | Yes | Yes | -\n| take | Yes | Yes | Yes\n| takeLast | - | Yes | -\n| takeWhile | Yes | Yes | -\n| toArray | No | Yes | -\n| trampoline | - | - | -\n| unapply | - | - | -\n| unary | - | - | -\n| uniq \u003csup\u003e4\u003csup\u003e | No | Yes | -\n| values | Yes | Yes | -\n| zip | Yes | Yes | Yes\n| zipAssoc | Yes | Yes | Yes\n| zipWith | Yes | Yes | Yes\n\n#### Notes\n\n1. `countBy` is not lazy in the sense that it return an `array` and not a generator **but** it is lazy in the sense that it will not convert the input into an array first so it will not blow the memory in case of processing huge data as input. But that assumes that the input is such that after processing the result will not be huge.\n2. For `flip` to work with a curried function, you _must_ pass its arity as a second parameter, otherwise it won't be able to detect it properly - example:  `$appendTo = P::flip('P::append', 2);`. In general, you should prefer specifying the arity even for non-curried functions because arity detection happens via `Reflection` which is problematic speed-wise.\n3. Returns a generator though.\n4. It is eager in converting the generator to an array.\n\n### Version Notes\n\nInitial release version is 0.9.0. It will remain \u003c 1.0 until sufficient feedback from usage allows for finalizing of the api. So expect things to change.\n\n### More?\n\nIf you are reading this, you are probably interested in investigating the use of Pramda in your work. I will be posting updates, examples and other useful resources on my site. [Add yourself to the notification system](https://app.mailerlite.com/webforms/landing/a6g7r6), it takes less that 9.73 seconds.\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkapolos%2Fpramda","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkapolos%2Fpramda","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkapolos%2Fpramda/lists"}