{"id":22092106,"url":"https://github.com/krakphp/fn","last_synced_at":"2025-07-24T20:31:58.493Z","repository":{"id":57009025,"uuid":"120550186","full_name":"krakphp/fn","owner":"krakphp","description":"Functional library for PHP with proper currying","archived":false,"fork":false,"pushed_at":"2022-12-07T16:47:14.000Z","size":181,"stargazers_count":23,"open_issues_count":3,"forks_count":4,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-11-14T16:38:33.187Z","etag":null,"topics":["code-generation","curry","functional","php"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/krakphp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-07T02:10:53.000Z","updated_at":"2024-02-20T07:09:35.000Z","dependencies_parsed_at":"2023-01-24T18:04:54.056Z","dependency_job_id":null,"html_url":"https://github.com/krakphp/fn","commit_stats":null,"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Ffn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Ffn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Ffn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Ffn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/krakphp","download_url":"https://codeload.github.com/krakphp/fn/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227476144,"owners_count":17779417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["code-generation","curry","functional","php"],"created_at":"2024-12-01T03:08:20.307Z","updated_at":"2024-12-01T03:08:21.368Z","avatar_url":"https://github.com/krakphp.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fun\n\nYet another functional library for PHP. What makes this library special is that it uses PHP Parser to generate curried versions of the non-curried implementations for best performance.\n\n## Installation\n\nInstall with composer at `krak/fn`\n\n## Usage\n\nAll functions are defined in `Krak\\Fun`, are not curried, and are data last. Curried versions of functions are defined `Kran\\Fun\\Curried`. Constants are also generated per function in `Krak\\Fun\\Consts`.\n\n```php\n\u003c?php\n\nuse function Krak\\Fun\\Curried\\{filter, map, op};\nuse function Krak\\Fun\\{compose};\nuse const Krak\\Fun\\Consts\\{toArray};\n\n$res = compose(\n    toArray,\n    map(op('*')(3)),\n    filter(op('\u003e')(2))\n)([1,2,3,4]);\nassert($res == [9, 12]);\n```\n\nCheck the `src/fn.php` for examples of all the functions.\n\n### Fun API\n\nIn addition to importing the functions/consts individually, you can also utilize the `f` and `c` namespaces as a shorthand which make using the library a lot easier.\n\n```php\n\u003c?php\n\nuse Krak\\Fun\\{f, c};\n\n$res = f\\compose(\n    c\\toArray,\n    c\\map(c\\op('*')(3)),\n    c\\filter(c\\op('\u003e')(2))\n)([1,2,3,4]);\nassert($res == [9, 12]);\n```\n\nThe `f` namespace holds the standard functions basically copied over verbatim from the `Krak\\Fun` namespace.\n\nThe `c` namespace contains all of the curried functions and constant definitions.\n\nOne great way to use the consts is with compose or pipe chains:\n\n```php\nuse Krak\\Fun\\{f, c};\n\n$res = f\\compose(\n    c\\toArray,\n    c\\map(function($tup) {\n        return $tup[0] + $tup[1];\n    }),\n    c\\toPairs\n)([1,2,3]);\n// $res == [1, 3, 5]\n```\n\n### Constants\n\nThis library generates constants with same name as the function they were generated from where their value is the fully qualified name of the function.\n\nPHP (unfortunately) will treat strings as callables if they resolve to a function name. So generating constants with the same name as functions allows us to support a neat first class function type syntax.\n\n```php\n\u003c?php\n\nuse Krak\\Fun\\{f, c};\n\nfunction getArrayRange(callable $toArray): array {\n    $toArray(f\\range(1,3));\n}\n\ngetArrayRange(c\\toArray);\n```\n\nThe above is valid php and will work because c\\toArray resolves to `Krak\\\\Fun\\\\toArray` which php will treat as a valid callable.\n\nThis is great for compose chains and partial application:\n\n```php\nuse Krak\\Fun\\{f, c};\n\n$res = f\\compose(\n    c\\toArray,\n    map(partial(c\\op, '*', 3))\n)([1,2,3]);\nassert($res == [3,6,9]);\n```\n\nThe `op` function is defined as `op($operator, $b, $a)`. Essentially, what we did was call: `partial('Krak\\\\Fun\\\\op', '*', 3)`.\n\n### Currying\n\nAll functions that are curryable have generated curry functions. A function is curryable if it has more than one required argument or one required argument with any number of optional arguments.\n\nThese function definitions aren't curryable:\n\n```php\nfunc()\nfunc($arg1)\nfunc($oarg = null, $oarg1 = null)\n```\n\nThese are:\n\n```php\nfunc($arg1, $arg2)\nfunc($arg1, $oarg = null)\n```\n\nGiven a function definition like:\n\n```\n(a, b, c = null) -\u003e Void\n```\n\nthe curried verison would look like:\n\n```\n(a, c = null) -\u003e (b) -\u003e Void\n```\n\n\n### Debugging\n\nIf you have a function compose chain and want to debug/test the result of any of the functions, you can do something like the following examples:\n\n1. Debug a single value:\n\n    ```php\n    f\\compose(\n        function() {}, // do something else\n        c\\dd(), // debug result here\n        function() {}, // do another thing that returns a single value\n        function() {} // do something\n    );\n    ```\n2. Debug an iterable:\n\n    ```php\n    f\\compose(\n        function() {}, // do something else\n        c\\dd(), c\\toArray, // debug result here\n        c\\map(function() {}) // do something\n    );\n    ```\n\n### Using Compose Chains for Readable Code\n\nOne of my favorite features of using this library is building compose chains in a way that make your application services a lot easier to read and follow along with.\n\n```php\n\nuse Krak\\Fun\\{f, c};\n\n/**\n * Fetches orders based off of the arguments, filters data, and imports to database\n */\nfinal class ImportOrdersFromApi\n{\n    public function __construct(ApiClient $client, OrderRepository $orderRepository, SaveOrders $saveOrders) {\n        // ...\n    }\n\n    public function __invoke(ImportOrderRequest $req): void {\n        f\\compose(\n            $this-\u003epersistApiOrders(),\n            $this-\u003eremoveAlreadyImportedOrders(),\n            $this-\u003efetchOrdersFromApi()\n        )($req);\n    }\n\n    private function persistApiOrders(): callable {\n        // important that this is an c\\each so that it will consume the iterable chain\n        return f\\compose(\n            c\\each($this-\u003esaveOrders), // saveOrders has a signature of `__invoke(iterable Order[]) =\u003e void`\n            c\\chunk(50), // chunk to persist many at once\n            c\\map(function(array $apiOrder) {\n                return Order::createFromApiData($apiOrder);\n            })\n        );\n    }\n\n    private function removeAlreadyImportedOrders(): callable {\n        return f\\compose(\n            c\\flatMap(function(array $apiOrders) {\n                $apiOrderIds = array_column($apiOrders, 'order_id');\n                /** array of order id =\u003e order entity */\n                $orders = $this-\u003eorderRepository-\u003efindByApiOrderIds($ids);\n                return f\\filter(function(array $apiOrder) use ($orders) {\n                    return !array_key_exists($apiOrder['order_id'], $orders);\n                }, $apiOrders);\n            }),\n            // chunk by 50 to save on database requests\n            c\\chunk(50)\n        );\n    }\n\n    /** Returns an iterable of api orders */\n    private function fetchOrdersFromApi(): callable {\n        return function(ImportOrderRequest $req) {\n            yield from $this-\u003eapiClient-\u003efetch(/* pass in req args */);\n        };\n    }\n}\n```\n\n## Docs\n\nDocs are generated with `make docs`. This uses Krak Peridocs to actually generate the documentation from the peridot tests.\n\n## Code Generation\n\nThe constants and curried functions are generated with `make code`.\n\n## Tests\n\nTests are run via `make test` and are stored in the `test` directory. We use peridot for testing.\n\n## API\n\u003ctable\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-all\"\u003eall\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-any\"\u003eany\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-arraycompact\"\u003earrayCompact\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-arrayfilter\"\u003earrayFilter\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-arraymap\"\u003earrayMap\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-arrayreindex\"\u003earrayReindex\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-arraywrap\"\u003earrayWrap\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-assign\"\u003eassign\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-chain\"\u003echain\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-chunk\"\u003echunk\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-chunkby\"\u003echunkBy\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-compact\"\u003ecompact\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-compose\"\u003ecompose\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-construct\"\u003econstruct\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-curry\"\u003ecurry\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-differencewith\"\u003edifferenceWith\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-dd\"\u003edd\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-drop\"\u003edrop\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-dropwhile\"\u003edropWhile\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-each\"\u003eeach\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-filter\"\u003efilter\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-filterkeys\"\u003efilterKeys\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-flatmap\"\u003eflatMap\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-flatten\"\u003eflatten\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-flip\"\u003eflip\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-frompairs\"\u003efromPairs\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-groupby\"\u003egroupBy\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-hasindexin\"\u003ehasIndexIn\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-head\"\u003ehead\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-inarray\"\u003einArray\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-index\"\u003eindex\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-indexin\"\u003eindexIn\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-indexof\"\u003eindexOf\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-isnull\"\u003eisNull\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-iter\"\u003eiter\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-join\"\u003ejoin\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-keys\"\u003ekeys\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-map\"\u003emap\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-mapaccum\"\u003emapAccum\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-mapkeys\"\u003emapKeys\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-mapkeyvalue\"\u003emapKeyValue\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-mapon\"\u003emapOn\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-nullable\"\u003enullable\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-oneach\"\u003eonEach\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-op\"\u003eop\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-pad\"\u003epad\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-partial\"\u003epartial\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-partition\"\u003epartition\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-pick\"\u003epick\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-pickby\"\u003epickBy\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-pipe\"\u003epipe\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-product\"\u003eproduct\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-prop\"\u003eprop\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-propin\"\u003epropIn\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-range\"\u003erange\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-reduce\"\u003ereduce\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-reducekeyvalue\"\u003ereduceKeyValue\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-reindex\"\u003ereindex\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-retry\"\u003eretry\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-search\"\u003esearch\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-setindex\"\u003esetIndex\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-setindexin\"\u003esetIndexIn\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-setprop\"\u003esetProp\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-slice\"\u003eslice\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-sortfromarray\"\u003esortFromArray\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-spread\"\u003espread\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-take\"\u003etake\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-takewhile\"\u003etakeWhile\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-tap\"\u003etap\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-throwif\"\u003ethrowIf\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-toarray\"\u003etoArray\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-toarraywithkeys\"\u003etoArrayWithKeys\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-topairs\"\u003etoPairs\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-updateindexin\"\u003eupdateIndexIn\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-values\"\u003evalues\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-when\"\u003ewhen\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-withstate\"\u003ewithState\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-within\"\u003ewithin\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-without\"\u003ewithout\u003c/a\u003e\u003c/td\u003e\u003ctd\u003e\u003ca href=\"#api-krak-fun-zip\"\u003ezip\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\n\u003ch3 id=\"api-krak-fun-all\"\u003eall(callable $predicate, iterable $iter): bool\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\all`\n\nReturns true if the predicate returns true on all of the items:\n\n```php\n$res = all(function ($v) {\n    return $v % 2 == 0;\n}, [2, 4, 6]);\nexpect($res)-\u003eequal(true);\n```\n\nReturns false if the predicate returns false on any of the items:\n\n```php\n$res = all(function ($v) {\n    return $v % 2 == 0;\n}, [1, 2, 4, 6]);\nexpect($res)-\u003eequal(false);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-any\"\u003eany(callable $predicate, iterable $iter): bool\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\any`\n\nReturns true if the predicate returns true on any of the items:\n\n```php\n$res = any(function ($v) {\n    return $v % 2 == 0;\n}, [1, 3, 4, 5]);\nexpect($res)-\u003eequal(true);\n```\n\nReturns false if the predicate returns false on all of the items:\n\n```php\n$res = any(function ($v) {\n    return $v % 2 == 0;\n}, [1, 3, 5]);\nexpect($res)-\u003eequal(false);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-arraycompact\"\u003earrayCompact(iterable $iter): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\arrayCompact`\n\nIt will remove all nulls from an iterable and return an array:\n\n```php\n$res = arrayCompact([1, 2, null, null, 3]);\nexpect(\\array_values($res))-\u003eequal([1, 2, 3]);\n```\n\nKeep in mind that the keys will be preserved when using arrayCompact, so make sure to use array_values if you want to ignore keys.\n\n\u003ch3 id=\"api-krak-fun-arrayfilter\"\u003earrayFilter(callable $fn, iterable $data): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\arrayFilter`\n\nAlias of array_filter:\n\n```php\n$res = arrayFilter(partial(op, '\u003c', 2), [1, 2, 3]);\nexpect($res)-\u003eequal([1]);\n```\n\nFilters iterables as well as arrays:\n\n```php\n$res = arrayFilter(partial(op, '\u003c', 2), range(1, 3));\nexpect($res)-\u003eequal([1]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-arraymap\"\u003earrayMap(callable $fn, iterable $data): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\arrayMap`\n\nAlias of array_map:\n\n```php\n$res = arrayMap(partial(op, '*', 2), [1, 2, 3]);\nexpect($res)-\u003eequal([2, 4, 6]);\n```\n\nMaps iterables as well as arrays:\n\n```php\n$res = arrayMap(partial(op, '*', 2), range(1, 3));\nexpect($res)-\u003eequal([2, 4, 6]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-arrayreindex\"\u003earrayReindex(callable $fn, iterable $iter): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\arrayReindex`\n\nRe-indexes a collection via a callable into an associative array:\n\n```php\n$res = arrayReindex(function ($v) {\n    return $v['id'];\n}, [['id' =\u003e 2], ['id' =\u003e 3], ['id' =\u003e 1]]);\nexpect($res)-\u003eequal([2 =\u003e ['id' =\u003e 2], 3 =\u003e ['id' =\u003e 3], 1 =\u003e ['id' =\u003e 1]]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-arraywrap\"\u003earrayWrap($value)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\arrayWrap`\n\nWraps any non list array into an array:\n\n```php\n$results = arrayMap(arrayWrap, [1, 'abc', ['a' =\u003e 1]]);\nexpect($results)-\u003eequal([[1], ['abc'], [['a' =\u003e 1]]]);\n```\n\nList based arrays are left as is:\n\n```php\n$results = arrayMap(arrayWrap, [[], [1, 2, 3]]);\nexpect($results)-\u003eequal([[], [1, 2, 3]]);\n```\n\nNote: `array_is_list` which requires php 8.1 or symfony/polyfill-php81\n\n\u003ch3 id=\"api-krak-fun-assign\"\u003eassign($obj, iterable $iter)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\assign`\n\nAssigns iterable keys and values to an object:\n\n```php\n$obj = new \\StdClass();\n$obj = assign($obj, ['a' =\u003e 1, 'b' =\u003e 2]);\nexpect($obj-\u003ea)-\u003eequal(1);\nexpect($obj-\u003eb)-\u003eequal(2);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-chain\"\u003echain(iterable ...$iters)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\chain`\n\nChains iterables together into one iterable:\n\n```php\n$res = chain([1], range(2, 3));\nexpect(toArray($res))-\u003eequal([1, 2, 3]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-chunk\"\u003echunk(int $size, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\chunk`\n\nChunks an iterable into equal sized chunks.:\n\n```php\n$res = chunk(2, [1, 2, 3, 4]);\nexpect(toArray($res))-\u003eequal([[1, 2], [3, 4]]);\n```\n\nIf there is any remainder, it is yielded as is:\n\n```php\n$res = chunk(3, [1, 2, 3, 4]);\nexpect(toArray($res))-\u003eequal([[1, 2, 3], [4]]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-chunkby\"\u003echunkBy(callable $fn, iterable $iter, ?int $maxSize = null): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\chunkBy`\n\nChunks items together off of the result from the callable:\n\n```php\n$items = ['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc'];\n$chunks = chunkBy(function (string $item) {\n    return $item[0];\n    // return first char\n}, $items);\nexpect(toArray($chunks))-\u003eequal([['aa', 'ab', 'ac'], ['ba', 'bb', 'bc'], ['ca', 'cb', 'cc']]);\n```\n\nAllows a maxSize to prevent chunks from exceeding a limit:\n\n```php\n$items = ['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc'];\n$chunks = chunkBy(function (string $item) {\n    return $item[0];\n    // return first char\n}, $items, 2);\nexpect(toArray($chunks))-\u003eequal([['aa', 'ab'], ['ac'], ['ba', 'bb'], ['bc'], ['ca', 'cb'], ['cc']]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-compact\"\u003ecompact(iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\compact`\n\nRemoves all null values from an iterable:\n\n```php\n$res = compact([1, null, 2, 3, null, null, 4]);\nexpect(toArray($res))-\u003eequal([1, 2, 3, 4]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-compose\"\u003ecompose(callable ...$fns)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\compose`\n\nComposes functions together. compose(f, g)(x) == f(g(x)):\n\n```php\n$mul2 = Curried\\op('*')(2);\n$add3 = Curried\\op('+')(3);\n$add3ThenMul2 = compose($mul2, $add3);\n$res = $add3ThenMul2(5);\nexpect($res)-\u003eequal(16);\n```\n\nAllows an empty initial argument:\n\n```php\n$res = compose(Curried\\reduce(function ($acc, $v) {\n    return $acc + $v;\n}, 0), function () {\n    yield from [1, 2, 3];\n})();\nexpect($res)-\u003eequal(6);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-construct\"\u003econstruct($className, ...$args)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\construct`\n\nConstructs (instantiates) a new class with the given arguments:\n\n```php\n$res = construct(\\ArrayObject::class, [1, 2, 3]);\nexpect($res-\u003ecount())-\u003eequal(3);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-curry\"\u003ecurry(callable $fn, int $num = 1)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\curry`\n\ncurrys the given function $n times:\n\n```php\n$res = curry(_idArgs::class, 2)(1)(2)(3);\nexpect($res)-\u003eequal([1, 2, 3]);\n```\n\nGiven a function definition: (a, b) -\u003e c. A curried version will look like (a) -\u003e (b) -\u003e c\n\n\u003ch3 id=\"api-krak-fun-differencewith\"\u003edifferenceWith(callable $cmp, iterable $a, iterable $b)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\differenceWith`\n\nTakes the difference between two iterables with a given comparator:\n\n```php\n$res = differenceWith(partial(op, '==='), [1, 2, 3, 4, 5], [2, 3, 4]);\nexpect(toArray($res))-\u003eequal([1, 5]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-dd\"\u003edd($value, callable $dump = null, callable $die = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\dd`\n\ndumps and dies:\n\n```php\n$res = null;\n$died = false;\n$dump = function ($v) use(\u0026$res) {\n    $res = $v;\n};\n$die = function () use(\u0026$died) {\n    $died = true;\n};\ndd(1, $dump, $die);\nexpect($res)-\u003eequal(1);\nexpect($died)-\u003eequal(true);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-drop\"\u003edrop(int $num, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\drop`\n\nDrops the first num items from an iterable:\n\n```php\n$res = drop(2, range(0, 3));\nexpect(toArray($res))-\u003eequal([2, 3]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-dropwhile\"\u003edropWhile(callable $predicate, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\dropWhile`\n\nDrops elements from the iterable while the predicate returns true:\n\n```php\n$res = dropWhile(Curried\\op('\u003e')(0), [2, 1, 0, 1, 2]);\nexpect(toArray($res))-\u003eequal([0, 1, 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-each\"\u003eeach(callable $handle, iterable $iter)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\each`\n\nInvokes a callable on each item in an iterable:\n\n```php\n$state = [(object) ['id' =\u003e 1], (object) ['id' =\u003e 2]];\neach(function ($item) {\n    $item-\u003eid += 1;\n}, $state);\nexpect([$state[0]-\u003eid, $state[1]-\u003eid])-\u003eequal([2, 3]);\n```\n\nNormally using php foreach should suffice for iterating over an iterable; however, php variables in foreach loops are not scoped whereas closures are.\n\n\u003ch3 id=\"api-krak-fun-filter\"\u003efilter(callable $predicate, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\filter`\n\nLazily filters an iterable off of a predicate that should return true or false. If true, keep the data, else remove the data from the iterable:\n\n```php\n$values = filter(partial(op, '\u003e', 2), [1, 2, 3, 4]);\n// keep all items that are greater than 2\nexpect(toArray($values))-\u003eequal([3, 4]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-filterkeys\"\u003efilterKeys(callable $predicate, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\filterKeys`\n\nFilters an iterable off of the keys:\n\n```php\n$res = filterKeys(Curried\\inArray(['a', 'b']), ['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3]);\nexpect(toArrayWithKeys($res))-\u003eequal(['a' =\u003e 1, 'b' =\u003e 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-flatmap\"\u003eflatMap(callable $map, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\flatMap`\n\nMaps and then flattens an iterable:\n\n```php\n$res = flatMap(function ($v) {\n    return [-$v, $v];\n}, range(1, 3));\nexpect(toArray($res))-\u003eequal([-1, 1, -2, 2, -3, 3]);\n```\n\nflatMap is perfect for when you want to map an iterable and also add elements to the resulting iterable.\n\n\u003ch3 id=\"api-krak-fun-flatten\"\u003eflatten(iterable $iter, $levels = INF): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\flatten`\n\nFlattens nested iterables into a flattened set of elements:\n\n```php\n$res = flatten([1, [2, [3, [4]]]]);\nexpect(toArray($res))-\u003eequal([1, 2, 3, 4]);\n```\n\nCan flatten a specific number of levels:\n\n```php\n$res = flatten([1, [2, [3]]], 1);\nexpect(toArray($res))-\u003eequal([1, 2, [3]]);\n```\n\nFlattening zero levels does nothing:\n\n```php\n$res = flatten([1, [2]], 0);\nexpect(toArray($res))-\u003eequal([1, [2]]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-flip\"\u003eflip(iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\flip`\n\nFlips the keys =\u003e values of an iterable to values =\u003e keys:\n\n```php\n$res = flip(['a' =\u003e 0, 'b' =\u003e 1]);\nexpect(toArray($res))-\u003eequal(['a', 'b']);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-frompairs\"\u003efromPairs(iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\fromPairs`\n\nConverts an iterable of tuples [$key, $value] into an associative iterable:\n\n```php\n$res = fromPairs([['a', 1], ['b', 2]]);\nexpect(toArrayWithKeys($res))-\u003eequal(['a' =\u003e 1, 'b' =\u003e 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-groupby\"\u003egroupBy(callable $fn, iterable $iter, ?int $maxSize = null): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\groupBy`\n\nAlias of chunkBy\n\nGroups items together off of the result from the callable:\n\n```php\n$items = ['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc'];\n$groupedItems = groupBy(function (string $item) {\n    return $item[0];\n    // return first char\n}, $items);\nexpect(toArray($groupedItems))-\u003eequal([['aa', 'ab', 'ac'], ['ba', 'bb', 'bc'], ['ca', 'cb', 'cc']]);\n```\n\nAllows a maxSize to prevent groups from exceeding a limit:\n\n```php\n$items = ['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc'];\n$groupedItems = groupBy(function (string $item) {\n    return $item[0];\n    // return first char\n}, $items, 2);\nexpect(toArray($groupedItems))-\u003eequal([['aa', 'ab'], ['ac'], ['ba', 'bb'], ['bc'], ['ca', 'cb'], ['cc']]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-hasindexin\"\u003ehasIndexIn(array $keys, array $data): bool\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\hasIndexIn`\n\nChecks if a nested index exists in the given data:\n\n```php\n$res = hasIndexIn(['a', 'b', 'c'], ['a' =\u003e ['b' =\u003e ['c' =\u003e null]]]);\nexpect($res)-\u003eequal(true);\n```\n\nReturns false if any of the indexes do not exist in the data:\n\n```php\n$res = hasIndexIn(['a', 'b', 'c'], ['a' =\u003e ['b' =\u003e []]]);\nexpect($res)-\u003eequal(false);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-head\"\u003ehead(iterable $iter)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\head`\n\nReturns the fist element in an iterable:\n\n```php\n$res = head([1, 2, 3]);\nexpect($res)-\u003eequal(1);\n```\n\nBut returns null if the iterable is empty:\n\n```php\n$res = head([]);\nexpect($res)-\u003eequal(null);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-inarray\"\u003einArray(array $set, $item): bool\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\inArray`\n\nChecks if an item is within an array of items:\n\n```php\n$res = inArray([1, 2, 3], 2);\nexpect($res)-\u003eequal(true);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-index\"\u003eindex($key, $data, $else = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\index`\n\nAccesses an index in an array:\n\n```php\n$res = index('a', ['a' =\u003e 1]);\nexpect($res)-\u003eequal(1);\n```\n\nIf no value exists at the given index, $else will be returned:\n\n```php\n$res = index('a', ['b' =\u003e 1], 2);\nexpect($res)-\u003eequal(2);\n```\n\nAlso works with objects that implement ArrayAccess:\n\n```php\nclass MyClass implements \\ArrayAccess\n{\n    private $container = [];\n    public function __construct()\n    {\n        $this-\u003econtainer = ['one' =\u003e 1, 'two' =\u003e 2];\n    }\n    public function offsetExists($offset)\n    {\n        return isset($this-\u003econtainer[$offset]);\n    }\n    public function offsetGet($offset)\n    {\n        return isset($this-\u003econtainer[$offset]) ? $this-\u003econtainer[$offset] : null;\n    }\n    public function offsetSet($offset, $value)\n    {\n        /* ... */\n    }\n    public function offsetUnset($offset)\n    {\n        /* ... */\n    }\n}\n$object = new MyClass();\nexpect(index('two', $object))-\u003eequal(2);\nexpect(index('three', $object, 'else'))-\u003eequal('else');\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-indexin\"\u003eindexIn(array $keys, array $data, $else = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\indexIn`\n\nAccesses a nested index in a deep array structure:\n\n```php\n$res = indexIn(['a', 'b'], ['a' =\u003e ['b' =\u003e 1]]);\nexpect($res)-\u003eequal(1);\n```\n\nIf any of the indexes do not exist, $else will be returned:\n\n```php\n$res = indexIn(['a', 'b'], ['a' =\u003e ['c' =\u003e 1]], 2);\nexpect($res)-\u003eequal(2);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-indexof\"\u003eindexOf(callable $predicate, iterable $iter)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\indexOf`\n\nSearches for an element and returns the key if found:\n\n```php\n$res = indexOf(partial(op, '==', 'b'), ['a', 'b', 'c']);\nexpect($res)-\u003eequal(1);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-isnull\"\u003eisNull($val)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\isNull`\n\nalias for is_null:\n\n```php\nexpect(isNull(null))-\u003eequal(true);\nexpect(isNull(0))-\u003eequal(false);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-iter\"\u003eiter($iter): \\Iterator\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\iter`\n\nConverts any iterable into a proper instance of Iterator.\n\nCan convert arrays:\n\n```php\nexpect(iter([1, 2, 3]))-\u003einstanceof('Iterator');\n```\n\nCan convert an Iterator:\n\n```php\nexpect(iter(new \\ArrayIterator([1, 2, 3])))-\u003einstanceof('Iterator');\n```\n\nCan convert objects:\n\n```php\n$obj = (object) ['a' =\u003e 1, 'b' =\u003e 2];\nexpect(iter($obj))-\u003einstanceof('Iterator');\nexpect(toArrayWithKeys(iter($obj)))-\u003eequal(['a' =\u003e 1, 'b' =\u003e 2]);\n```\n\nCan convert any iterable:\n\n```php\n$a = new class implements \\IteratorAggregate\n{\n    public function getIterator()\n    {\n        return new \\ArrayIterator([1, 2, 3]);\n    }\n};\nexpect(iter($a))-\u003einstanceof('Iterator');\nexpect(toArray(iter($a)))-\u003eequal([1, 2, 3]);\n```\n\nCan convert strings:\n\n```php\nexpect(iter('abc'))-\u003einstanceof('Iterator');\nexpect(toArray(iter('abc')))-\u003eequal(['a', 'b', 'c']);\n```\n\nWill throw an exception otherwise:\n\n```php\nexpect(function () {\n    iter(1);\n})-\u003ethrow('LogicException', 'Iter could not be converted into an iterable.');\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-join\"\u003ejoin(string $sep, iterable $iter)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\join`\n\nJoins an iterable with a given separator:\n\n```php\n$res = join(\",\", range(1, 3));\nexpect($res)-\u003eequal(\"1,2,3\");\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-keys\"\u003ekeys(iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\keys`\n\nYields only the keys of an in iterable:\n\n```php\n$keys = keys(['a' =\u003e 1, 'b' =\u003e 2]);\nexpect(toArray($keys))-\u003eequal(['a', 'b']);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-map\"\u003emap(callable $predicate, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\map`\n\nLazily maps an iterable's values to a different set:\n\n```php\n$values = map(partial(op, '*', 2), [1, 2, 3, 4]);\nexpect(toArray($values))-\u003eequal([2, 4, 6, 8]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-mapaccum\"\u003emapAccum(callable $fn, iterable $iter, $acc = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\mapAccum`\n\nMaps a function to each element of a list while passing in an accumulator to accumulate over every iteration:\n\n```php\n$data = iter('abcd');\n[$totalSort, $values] = mapAccum(function ($acc, $value) {\n    return [$acc + 1, ['name' =\u003e $value, 'sort' =\u003e $acc]];\n}, iter('abcd'), 0);\nexpect($totalSort)-\u003eequal(4);\nexpect($values)-\u003eequal([['name' =\u003e 'a', 'sort' =\u003e 0], ['name' =\u003e 'b', 'sort' =\u003e 1], ['name' =\u003e 'c', 'sort' =\u003e 2], ['name' =\u003e 'd', 'sort' =\u003e 3]]);\n```\n\nNote: mapAccum converts the interable into an array and is not lazy like most of the other functions in this library\n\n\u003ch3 id=\"api-krak-fun-mapkeys\"\u003emapKeys(callable $predicate, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\mapKeys`\n\nLazily maps an iterable's keys to a different set:\n\n```php\n$keys = mapKeys(partial(op, '.', '_'), ['a' =\u003e 1, 'b' =\u003e 2]);\nexpect(toArrayWithKeys($keys))-\u003eequal(['a_' =\u003e 1, 'b_' =\u003e 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-mapkeyvalue\"\u003emapKeyValue(callable $fn, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\mapKeyValue`\n\nLazily maps an iterable's key/value tuples to a different set:\n\n```php\n$keys = mapKeyValue(function ($kv) {\n    [$key, $value] = $kv;\n    return [\"{$key}_\", $value * $value];\n}, ['a' =\u003e 1, 'b' =\u003e 2]);\nexpect(toArrayWithKeys($keys))-\u003eequal(['a_' =\u003e 1, 'b_' =\u003e 4]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-mapon\"\u003emapOn(array $maps, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\mapOn`\n\nMaps values on specific keys:\n\n```php\n$values = mapOn(['a' =\u003e partial(op, '*', 3), 'b' =\u003e partial(op, '+', 1)], ['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3]);\nexpect(toArray($values))-\u003eequal([3, 3, 3]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-nullable\"\u003enullable(callable $fn, $value)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\nullable`\n\nPerforms the callable if the value is not null:\n\n```php\nexpect(nullable('intval', '0'))-\u003eequal(0);\n```\n\nReturns null if the value is null:\n\n```php\nexpect(nullable('intval', null))-\u003eequal(null);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-oneach\"\u003eonEach(callable $handle, iterable $iter)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\onEach`\n\nDuplicate of each.\n\nInvokes a callable on each item in an iterable:\n\n```php\n$state = [(object) ['id' =\u003e 1], (object) ['id' =\u003e 2]];\nonEach(function ($item) {\n    $item-\u003eid += 1;\n}, $state);\nexpect([$state[0]-\u003eid, $state[1]-\u003eid])-\u003eequal([2, 3]);\n```\n\nNormally using php foreach should suffice for iterating over an iterable; however, php variables in foreach loops are not scoped whereas closures are.\n\n\u003ch3 id=\"api-krak-fun-op\"\u003eop(string $op, $b, $a)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\op`\n\nop evaluates binary operations. It expects the right hand operator first which makes most sense when currying or partially applying the op function.\nWhen reading the op func, it should be read: `evaluate $op with $b with $a` e.g.:\n\n```\nop('+', 2, 3) -\u003e add 2 with 3\nop('-', 2, 3) -\u003e subtract 2 from 3\nop('\u003e', 2, 3) =\u003e compare greater than 2 with 3\n```\n\nEvaluates two values with a given operator:\n\n```php\n$res = op('\u003c', 2, 1);\nexpect($res)-\u003eequal(true);\n```\n\nSupports equality operators:\n\n```php\n$obj = new stdClass();\n$ops = [['==', [1, 1]], ['eq', [2, 2]], ['!=', [1, 2]], ['neq', [2, 3]], ['===', [$obj, $obj]], ['!==', [new stdClass(), new stdClass()]], ['\u003e', [1, 2]], ['gt', [1, 3]], ['\u003e=', [1, 2]], ['gte', [1, 1]], ['\u003c', [2, 1]], ['lt', [3, 1]], ['\u003c=', [2, 1]], ['lte', [1, 1]]];\nforeach ($ops as list($op, list($b, $a))) {\n    $res = op($op, $b, $a);\n    expect($res)-\u003eequal(true);\n}\n```\n\nSupports other operators:\n\n```php\n$ops = [['+', [2, 3], 5], ['-', [2, 3], 1], ['*', [2, 3], 6], ['**', [2, 3], 9], ['/', [2, 3], 1.5], ['%', [2, 3], 1], ['.', ['b', 'a'], 'ab']];\nforeach ($ops as list($op, list($b, $a), $expected)) {\n    $res = op($op, $b, $a);\n    expect($res)-\u003eequal($expected);\n}\n```\n\nIs more useful partially applied or curried:\n\n```php\n$add2 = Curried\\op('+')(2);\n$mul3 = partial(op, '*', 3);\n$sub4 = Curried\\op('-')(4);\n// ((2 + 2) * 3) - 4\n$res = compose($sub4, $mul3, $add2)(2);\nexpect($res)-\u003eequal(8);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-pad\"\u003epad(int $size, iterable $iter, $padValue = null): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\pad`\n\nPads an iterable to a specific size:\n\n```php\n$res = pad(5, [1, 2, 3]);\nexpect(toArray($res))-\u003eequal([1, 2, 3, null, null]);\n```\n\nAllows custom pad values:\n\n```php\n$res = pad(5, [1, 2, 3], 0);\nexpect(toArray($res))-\u003eequal([1, 2, 3, 0, 0]);\n```\n\nPads nothing if iterable is the same size as pad size:\n\n```php\n$res = pad(5, [1, 2, 3, 4, 5]);\nexpect(toArray($res))-\u003eequal([1, 2, 3, 4, 5]);\n```\n\nPads nothing if iterable is greater than pad size:\n\n```php\n$res = pad(5, [1, 2, 3, 4, 5, 6]);\nexpect(toArray($res))-\u003eequal([1, 2, 3, 4, 5, 6]);\n```\n\nIgnores keys of original iterable:\n\n```php\n$res = pad(3, ['a' =\u003e 1, 'b' =\u003e 2]);\nexpect(toArrayWithKeys($res))-\u003eequal([1, 2, null]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-partial\"\u003epartial(callable $fn, ...$appliedArgs)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\partial`\n\nPartially applies arguments to a function. Given a function signature like f = (a, b, c) -\u003e d, partial(f, a, b) -\u003e (c) -\u003e d:\n\n```php\n$fn = function ($a, $b, $c) {\n    return ($a + $b) * $c;\n};\n$fn = partial($fn, 1, 2);\n// apply the two arguments (a, b) and return a new function with signature (c) -\u003e d\nexpect($fn(3))-\u003eequal(9);\n```\n\nYou can also use place holders when partially applying:\n\n```php\n$fn = function ($a, $b, $c) {\n    return ($a + $b) * $c;\n};\n// _() represents a placeholder for parameter b.\n$fn = partial($fn, 1, _(), 3);\n// create the new func with signature (b) -\u003e d\nexpect($fn(2))-\u003eequal(9);\n```\n\nFull partial application also works:\n\n```php\n$fn = function ($a, $b) {\n    return [$a, $b];\n};\n$fn = partial($fn, 1, 2);\nexpect($fn())-\u003eequal([1, 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-partition\"\u003epartition(callable $partition, iterable $iter, int $numParts = 2): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\partition`\n\nSplits an iterable into different arrays based off of a predicate. The predicate should return the index to partition the data into:\n\n```php\nlist($left, $right) = partition(function ($v) {\n    return $v \u003c 3 ? 0 : 1;\n}, [1, 2, 3, 4]);\nexpect([$left, $right])-\u003eequal([[1, 2], [3, 4]]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-pick\"\u003epick(iterable $fields, array $data): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\pick`\n\nPicks only the given fields from a structured array:\n\n```php\n$res = pick(['a', 'b'], ['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3]);\nexpect($res)-\u003eequal(['a' =\u003e 1, 'b' =\u003e 2]);\n```\n\nCan be used in curried form:\n\n```php\n$res = arrayMap(Curried\\pick(['id', 'name']), [['id' =\u003e 1, 'name' =\u003e 'Foo', 'slug' =\u003e 'foo'], ['id' =\u003e 2, 'name' =\u003e 'Bar', 'slug' =\u003e 'bar']]);\nexpect($res)-\u003eequal([['id' =\u003e 1, 'name' =\u003e 'Foo'], ['id' =\u003e 2, 'name' =\u003e 'Bar']]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-pickby\"\u003epickBy(callable $pick, array $data): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\pickBy`\n\nPicks only the fields that match the pick function from a structured array:\n\n```php\n$res = pickBy(Curried\\spread(function (string $key, int $value) : bool {\n    return $value % 2 === 0;\n}), ['a' =\u003e 1, 'b' =\u003e 2, 'c' =\u003e 3]);\nexpect($res)-\u003eequal(['b' =\u003e 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-pipe\"\u003epipe(callable ...$fns)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\pipe`\n\nCreates a function that pipes values from one func to the next.:\n\n```php\n$add3 = Curried\\op('+')(3);\n$mul2 = Curried\\op('*')(2);\n$add3ThenMul2 = pipe($add3, $mul2);\n$res = $add3ThenMul2(5);\nexpect($res)-\u003eequal(16);\n```\n\nAllows an empty initial argument:\n\n```php\n$res = pipe(function () {\n    yield from [1, 2, 3];\n}, Curried\\reduce(function ($acc, $v) {\n    return $acc + $v;\n}, 0))();\nexpect($res)-\u003eequal(6);\n```\n\n`pipe` and `compose` are sister functions and do the same thing except the functions are composed in reverse order. pipe(f, g)(x) = g(f(x))\n\n\u003ch3 id=\"api-krak-fun-product\"\u003eproduct(iterable ...$iters): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\product`\n\nCreates a cartesian product of multiple sets:\n\n```php\n$res = product([1, 2], [3, 4], [5, 6]);\nexpect(toArray($res))-\u003eequal([[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-prop\"\u003eprop(string $key, $data, $else = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\prop`\n\nAccesses a property from an object:\n\n```php\n$obj = new \\StdClass();\n$obj-\u003eid = 1;\n$res = prop('id', $obj);\nexpect($res)-\u003eequal(1);\n```\n\nIf no property exists, it will return the $else value:\n\n```php\n$obj = new \\StdClass();\n$res = prop('id', $obj, 2);\nexpect($res)-\u003eequal(2);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-propin\"\u003epropIn(array $props, $obj, $else = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\propIn`\n\nAccesses a property deep in an object tree:\n\n```php\n$obj = new \\StdClass();\n$obj-\u003eid = 1;\n$obj-\u003echild = new \\StdClass();\n$obj-\u003echild-\u003eid = 2;\n$res = propIn(['child', 'id'], $obj);\nexpect($res)-\u003eequal(2);\n```\n\nIf any property is missing in the tree, it will return the $else value:\n\n```php\n$obj = new \\StdClass();\n$obj-\u003eid = 1;\n$obj-\u003echild = new \\StdClass();\n$res = propIn(['child', 'id'], $obj, 3);\nexpect($res)-\u003eequal(3);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-range\"\u003erange($start, $end, $step = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\range`\n\nCreates an iterable of a range of values starting from $start going to $end inclusively incrementing by $step:\n\n```php\n$res = range(1, 3);\nexpect(toArray($res))-\u003eequal([1, 2, 3]);\n```\n\nIt also allows a decreasing range:\n\n```php\n$res = range(3, 1);\nexpect(toArray($res))-\u003eequal([3, 2, 1]);\n```\n\nAn exception will be thrown if the $step provided goes in the wrong direction:\n\n```php\nexpect(function () {\n    toArray(range(1, 2, -1));\n})-\u003ethrow(\\InvalidArgumentException::class);\nexpect(function () {\n    toArray(range(2, 1, 1));\n})-\u003ethrow(\\InvalidArgumentException::class);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-reduce\"\u003ereduce(callable $reduce, iterable $iter, $acc = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\reduce`\n\nReduces an iterable into a single value:\n\n```php\n$res = reduce(function ($acc, $v) {\n    return $acc + $v;\n}, range(1, 3), 0);\nexpect($res)-\u003eequal(6);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-reducekeyvalue\"\u003ereduceKeyValue(callable $reduce, iterable $iter, $acc = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\reduceKeyValue`\n\nReduces an iterables key value pairs into a value:\n\n```php\n$res = reduceKeyValue(function ($acc, $kv) {\n    [$key, $value] = $kv;\n    return $acc . $key . $value;\n}, fromPairs([['a', 1], ['b', 2]]), \"\");\nexpect($res)-\u003eequal(\"a1b2\");\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-reindex\"\u003ereindex(callable $fn, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\reindex`\n\nRe-indexes a collection via a callable:\n\n```php\n$res = reindex(function ($v) {\n    return $v['id'];\n}, [['id' =\u003e 2], ['id' =\u003e 3], ['id' =\u003e 1]]);\nexpect(toArrayWithKeys($res))-\u003eequal([2 =\u003e ['id' =\u003e 2], 3 =\u003e ['id' =\u003e 3], 1 =\u003e ['id' =\u003e 1]]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-retry\"\u003eretry(callable $fn, $shouldRetry = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\retry`\n\nExecutes a function and retries if an exception is thrown:\n\n```php\n$i = 0;\n$res = retry(function () use(\u0026$i) {\n    $i += 1;\n    if ($i \u003c= 1) {\n        throw new \\Exception('bad');\n    }\n    return $i;\n});\nexpect($res)-\u003eequal(2);\n```\n\nOnly retries $maxTries times else it gives up and bubbles the exception:\n\n```php\nexpect(function () {\n    $i = 0;\n    retry(function () use(\u0026$i) {\n        $i += 1;\n        throw new \\Exception((string) $i);\n    }, 5);\n})-\u003ethrow('Exception', '6');\n```\n\nRetries until $shouldRetry returns false:\n\n```php\n$i = 0;\nexpect(function () {\n    $res = retry(function () use(\u0026$i) {\n        $i += 1;\n        throw new \\Exception((string) $i);\n    }, function ($numRetries, \\Throwable $t = null) {\n        return $numRetries \u003c 2;\n    });\n})-\u003ethrow('Exception', '2');\n```\n\nSends numRetries into the main fn:\n\n```php\n$res = retry(function ($numRetries) {\n    if (!$numRetries) {\n        throw new Exception('bad');\n    }\n    return $numRetries;\n}, 2);\nexpect($res)-\u003eequal(1);\n```\n\nKeep in mind that maxTries determines the number of *re*-tries. This means the function will execute maxTries + 1 times since the first invocation is not a retry.\n\n\u003ch3 id=\"api-krak-fun-search\"\u003esearch(callable $predicate, iterable $iter)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\search`\n\nSearches for an element in a collection where the callable returns true:\n\n```php\n$res = search(function ($v) {\n    return $v['id'] == 2;\n}, [['id' =\u003e 1], ['id' =\u003e 2], ['id' =\u003e 3]]);\nexpect($res)-\u003eequal(['id' =\u003e 2]);\n```\n\nReturns null if no element was found:\n\n```php\n$res = search(function ($v) {\n    return false;\n}, [['id' =\u003e 1], ['id' =\u003e 2], ['id' =\u003e 3]]);\nexpect($res)-\u003eequal(null);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-setindex\"\u003esetIndex($key, $value, array $data)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\setIndex`\n\nSets an index in an array:\n\n```php\n$res = setIndex('a', 1, []);\nexpect($res['a'])-\u003eequal(1);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-setindexin\"\u003esetIndexIn(array $keys, $value, array $data)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\setIndexIn`\n\nSets a nested index in an array:\n\n```php\n$res = setIndexIn(['a', 'b'], 1, ['a' =\u003e []]);\nexpect($res['a']['b'])-\u003eequal(1);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-setprop\"\u003esetProp(string $key, $value, $data)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\setProp`\n\nSets a property in an object:\n\n```php\n$res = setProp('a', 1, (object) []);\nexpect($res-\u003ea)-\u003eequal(1);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-slice\"\u003eslice(int $start, iterable $iter, $length = INF): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\slice`\n\nIt takes an inclusive slice from start to a given length of an interable:\n\n```php\n$sliced = slice(1, range(0, 4), 2);\nexpect(toArray($sliced))-\u003eequal([1, 2]);\n```\n\nIf length is not supplied it default to the end of the iterable:\n\n```php\n$sliced = slice(2, range(0, 4));\nexpect(toArray($sliced))-\u003eequal([2, 3, 4]);\n```\n\nwill not consume the iterator once the slice has been yielded:\n\n```php\n$i = 0;\n$gen = function () use(\u0026$i) {\n    foreach (range(0, 4) as $v) {\n        $i = $v;\n        (yield $i);\n    }\n};\n$sliced = toArray(slice(1, $gen(), 2));\nexpect($sliced)-\u003eequal([1, 2]);\nexpect($i)-\u003eequal(2);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-sortfromarray\"\u003esortFromArray(callable $fn, array $orderedElements, iterable $iter): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\sortFromArray`\n\nSort an iterable with a given array of ordered elements to sort by:\n\n```php\n$data = [['id' =\u003e 1, 'name' =\u003e 'A'], ['id' =\u003e 2, 'name' =\u003e 'B'], ['id' =\u003e 3, 'name' =\u003e 'C']];\n$res = sortFromArray(Curried\\index('id'), [2, 3, 1], $data);\nexpect(arrayMap(Curried\\index('name'), $res))-\u003eequal(['B', 'C', 'A']);\n```\n\nThrows an exception if any item in the iterable is not within the orderedElements:\n\n```php\nexpect(function () {\n    $data = [['id' =\u003e 1]];\n    $res = sortFromArray(Curried\\index('id'), [], $data);\n})-\u003ethrow(\\LogicException::class, 'Cannot sort element key 1 because it does not exist in the ordered elements.');\n```\n\nI've found this to be very useful when you fetch records from a database with a WHERE IN clause, and you need to make sure the results are in the same order as the ids in the WHERE IN clause.\n\n\u003ch3 id=\"api-krak-fun-spread\"\u003espread(callable $fn, array $data)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\spread`\n\nSpreads an array of arguments to a callable:\n\n```php\n$res = spread(function ($a, $b) {\n    return $a . $b;\n}, ['a', 'b']);\nexpect($res)-\u003eequal('ab');\n```\n\nCan be used in the curried form to unpack tuple arguments:\n\n```php\n$res = arrayMap(Curried\\spread(function (string $first, int $second) {\n    return $first . $second;\n}), [['a', 1], ['b', 2]]);\nexpect($res)-\u003eequal(['a1', 'b2']);\n```\n\nNote: this is basically just an alias for `call_user_func_array` or simply a functional wrapper around the `...` (spread) operator.\n\n\u003ch3 id=\"api-krak-fun-take\"\u003etake(int $num, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\take`\n\nTakes the first num items from an iterable:\n\n```php\n$res = take(2, range(0, 10));\nexpect(toArray($res))-\u003eequal([0, 1]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-takewhile\"\u003etakeWhile(callable $predicate, iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\takeWhile`\n\nTakes elements from an iterable while the $predicate returns true:\n\n```php\n$res = takeWhile(Curried\\op('\u003e')(0), [2, 1, 0, 1, 2]);\nexpect(toArray($res))-\u003eequal([2, 1]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-tap\"\u003etap(callable $tap, $value)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\tap`\n\nCalls given tap function on value and returns value:\n\n```php\n$loggedValues = [];\n$res = tap(function (string $v) use(\u0026$loggedValues) {\n    $loggedValues[] = $v;\n}, 'abc');\nexpect([$loggedValues[0], $res])-\u003eequal(['abc', 'abc']);\n```\n\n`tap` is useful anytime you need to operate on a value and do not want to modify the return value.\n\n\u003ch3 id=\"api-krak-fun-throwif\"\u003ethrowIf(callable $throw, callable $if, $value)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\throwIf`\n\nThrows the given exception if value given evaluates to true:\n\n```php\nexpect(function () {\n    throwIf(function (int $value) {\n        return new RuntimeException('Error: ' . $value);\n    }, function (int $value) {\n        return $value === 0;\n    }, 0);\n})-\u003ethrow(RuntimeException::class, 'Error: 0');\n```\n\nReturns given value if value evaluates to false:\n\n```php\n$res = throwIf(function (int $value) {\n    return new RuntimeException('Error: ' . $value);\n}, function (int $value) {\n    return $value === 0;\n}, 1);\nexpect($res)-\u003eequal(1);\n```\n\nNote: works best with short closures!\n\n\u003ch3 id=\"api-krak-fun-toarray\"\u003etoArray(iterable $iter): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\toArray`\n\nwill tranform any iterable into an array:\n\n```php\n$res = toArray((function () {\n    (yield 1);\n    (yield 2);\n    (yield 3);\n})());\nexpect($res)-\u003eequal([1, 2, 3]);\n```\n\ncan also be used as a constant:\n\n```php\n$res = compose(toArray, id)((function () {\n    (yield 1);\n    (yield 2);\n    (yield 3);\n})());\nexpect($res)-\u003eequal([1, 2, 3]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-toarraywithkeys\"\u003etoArrayWithKeys(iterable $iter): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\toArrayWithKeys`\n\ncan convert to an array and keep the keys:\n\n```php\n$gen = function () {\n    (yield 'a' =\u003e 1);\n    (yield 'b' =\u003e 2);\n};\nexpect(toArrayWithKeys($gen()))-\u003eequal(['a' =\u003e 1, 'b' =\u003e 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-topairs\"\u003etoPairs(iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\toPairs`\n\nTransforms an associative array into an iterable of tuples [$key, $value]:\n\n```php\n$res = toPairs(['a' =\u003e 1, 'b' =\u003e 2]);\nexpect(toArray($res))-\u003eequal([['a', 1], ['b', 2]]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-updateindexin\"\u003eupdateIndexIn(array $keys, callable $update, array $data): array\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\updateIndexIn`\n\nUpdates a nested element within a deep array structure:\n\n```php\n$data = ['a' =\u003e ['b' =\u003e ['c' =\u003e 3]]];\n$data = updateIndexIn(['a', 'b', 'c'], function ($v) {\n    return $v * $v;\n}, $data);\nexpect($data)-\u003eequal(['a' =\u003e ['b' =\u003e ['c' =\u003e 9]]]);\n```\n\nThrows an exception if nested key does not exist:\n\n```php\nexpect(function () {\n    $data = ['a' =\u003e ['b' =\u003e ['c' =\u003e 9]]];\n    updateIndexIn(['a', 'c', 'c'], function () {\n    }, $data);\n})-\u003ethrow(\\RuntimeException::class, 'Could not updateIn because the keys a -\u003e c -\u003e c could not be found.');\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-values\"\u003evalues(iterable $iter): iterable\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\values`\n\nExports only the values of an iterable:\n\n```php\n$res = values(['a' =\u003e 1, 'b' =\u003e 2]);\nexpect(toArrayWithKeys($res))-\u003eequal([1, 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-when\"\u003ewhen(callable $if, callable $then, $value)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\when`\n\nEvaluates the given value with the $then callable if the predicate returns true:\n\n```php\n$if = function ($v) {\n    return $v == 3;\n};\n$then = function ($v) {\n    return $v * $v;\n};\n$res = when($if, $then, 3);\nexpect($res)-\u003eequal(9);\n```\n\nBut will return the given value if the predicate returns false:\n\n```php\n$if = function ($v) {\n    return $v == 3;\n};\n$then = function ($v) {\n    return $v * $v;\n};\n$res = when($if, $then, 4);\nexpect($res)-\u003eequal(4);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-withstate\"\u003ewithState(callable $fn, $initialState = null)\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\withState`\n\nDecorate a function with accumulating state:\n\n```php\n$fn = withState(function ($state, $v) {\n    return [$state + 1, $state . ': ' . $v];\n}, 1);\n$res = arrayMap($fn, iter('abcd'));\nexpect($res)-\u003eequal(['1: a', '2: b', '3: c', '4: d']);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-within\"\u003ewithin(array $fields, iterable $iter): \\Iterator\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\within`\n\nOnly allows keys within the given array to stay:\n\n```php\n$data = flip(iter('abcd'));\n$res = within(['a', 'c'], $data);\nexpect(toArrayWithKeys($res))-\u003eequal(['a' =\u003e 0, 'c' =\u003e 2]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-without\"\u003ewithout(array $fields, iterable $iter): \\Iterator\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\without`\n\nFilters an iterable to be without the given keys:\n\n```php\n$data = flip(iter('abcd'));\n$res = without(['a', 'c'], $data);\nexpect(toArrayWithKeys($res))-\u003eequal(['b' =\u003e 1, 'd' =\u003e 3]);\n```\n\n\n\n\u003ch3 id=\"api-krak-fun-zip\"\u003ezip(iterable ...$iters): \\Iterator\u003c/h3\u003e\n\n**Name:** `Krak\\Fun\\zip`\n\nZips multiple iterables into an iterable n-tuples:\n\n```php\n$res = zip(iter('abc'), range(1, 3), [4, 5, 6]);\nexpect(toArray($res))-\u003eequal([['a', 1, 4], ['b', 2, 5], ['c', 3, 6]]);\n```\n\nReturns an empty iterable if no iters are present:\n\n```php\nexpect(toArray(zip()))-\u003eequal([]);\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrakphp%2Ffn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkrakphp%2Ffn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrakphp%2Ffn/lists"}