{"id":13831984,"url":"https://github.com/palatable/lambda","last_synced_at":"2026-01-30T11:52:21.836Z","repository":{"id":13570536,"uuid":"16262958","full_name":"palatable/lambda","owner":"palatable","description":"Functional patterns for Java","archived":false,"fork":false,"pushed_at":"2023-05-01T22:12:47.000Z","size":5844,"stargazers_count":877,"open_issues_count":17,"forks_count":85,"subscribers_count":42,"default_branch":"master","last_synced_at":"2025-10-16T17:30:32.781Z","etag":null,"topics":["algebraic-data-types","bifunctors","coproduct","either","functional-programming","functor","hlist","io-monad","java","lambda","lenses","maybe-monad","monad","monoid","optics","profunctors","semigroup","traversable","try-monad","tuples"],"latest_commit_sha":null,"homepage":"https://palatable.github.io/lambda/","language":"Java","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/palatable.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"github":["jnape"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2014-01-26T22:09:10.000Z","updated_at":"2025-10-03T04:35:10.000Z","dependencies_parsed_at":"2023-09-29T00:23:18.732Z","dependency_job_id":null,"html_url":"https://github.com/palatable/lambda","commit_stats":{"total_commits":698,"total_committers":17,"mean_commits":41.05882352941177,"dds":0.08022922636103147,"last_synced_commit":"d360ae809f27670219523e8819b4c0e65a36dd94"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/palatable/lambda","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Flambda","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Flambda/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Flambda/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Flambda/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/palatable","download_url":"https://codeload.github.com/palatable/lambda/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palatable%2Flambda/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28912098,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T08:15:08.179Z","status":"ssl_error","status_checked_at":"2026-01-30T08:14:31.507Z","response_time":66,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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":["algebraic-data-types","bifunctors","coproduct","either","functional-programming","functor","hlist","io-monad","java","lambda","lenses","maybe-monad","monad","monoid","optics","profunctors","semigroup","traversable","try-monad","tuples"],"created_at":"2024-08-04T10:01:46.647Z","updated_at":"2026-01-30T11:52:21.821Z","avatar_url":"https://github.com/palatable.png","language":"Java","readme":"λ\n======\n[![Actions Status](https://github.com/palatable/lambda/workflows/Java%20CI/badge.svg)](https://github.com/palatable/lambda/actions)\n[![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda)\n[\u003cimg src=\"https://dcbadge.vercel.app/api/server/wR7k8RAKM5\" height=20 alt=\"Join the chat on Discord\" /\u003e](https://discord.gg/wR7k8RAKM5)\n[![Floobits Status](https://floobits.com/jnape/lambda.svg)](https://floobits.com/jnape/lambda/redirect)\n\nFunctional patterns for Java\n\n#### Table of Contents\n\n - [Background](#background)\n - [Installation](#installation)\n - [Examples](#examples)\n - [Semigroups](#semigroups)\n - [Monoids](#monoids)\n - [Functors](#functors)\n   - [Bifunctors](#bifunctors)\n   - [Profunctors](#profunctors)\n   - [Applicatives](#applicatives)\n   - [Monads](#monads)\n   - [Traversables](#traversables)\n - [ADTs](#adts)\n   - [Maybe](#maybe)\n   - [HList](#hlist)\n     - [Tuples](#tuples)\n   - [HMaps](#hmaps)\n   - [CoProducts](#coproducts)\n     - [Either](#either)\n - [Lenses](#lenses)\n - [Notes](#notes)\n - [Ecosystem](#ecosystem)\n - [License](#license)\n\n\u003ca name=\"background\"\u003eBackground\u003c/a\u003e\n----------\n\nLambda was born out of a desire to use some of the same canonical functions (e.g. `unfoldr`, `takeWhile`, `zipWith`) and functional patterns (e.g. `Functor` and friends) that are idiomatic in other languages and make them available for Java.\n\nSome things a user of lambda most likely values:\n\n- Lazy evaluation\n- Immutability by design\n- Composition\n- Higher-level abstractions\n- Parametric polymorphism\n\nGenerally, everything that lambda produces is lazily-evaluated (except for terminal operations like `reduce`), immutable (except for `Iterator`s, since it's effectively impossible), composable (even between different arities, where possible), foundational (maximally contravariant), and parametrically type-checked (even where this adds unnecessary constraints due to a lack of higher-kinded types).\n\nAlthough the library is currently (very) small, these values should always be the driving forces behind future growth.\n\n\u003ca name=\"installation\"\u003eInstallation\u003c/a\u003e\n------------\n\nAdd the following dependency to your:\n\n`pom.xml` ([Maven](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)):\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.jnape.palatable\u003c/groupId\u003e\n    \u003cartifactId\u003elambda\u003c/artifactId\u003e\n    \u003cversion\u003e5.4.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n`build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)):\n\n```gradle\ncompile group: 'com.jnape.palatable', name: 'lambda', version: '5.4.0'\n```\n\n\u003ca name=\"examples\"\u003eExamples\u003c/a\u003e\n--------\n\nFirst, the obligatory `map`/`filter`/`reduce` example:\n```Java\nMaybe\u003cInteger\u003e sumOfEvenIncrements =\n          reduceLeft((x, y) -\u003e x + y,\n              filter(x -\u003e x % 2 == 0,\n                  map(x -\u003e x + 1, asList(1, 2, 3, 4, 5))));\n//-\u003e Just 12\n```\n\nEvery function in lambda is [curried](https://www.wikiwand.com/en/Currying), so we could have also done this:\n```Java\nFn1\u003cIterable\u003cInteger\u003e, Maybe\u003cInteger\u003e\u003e sumOfEvenIncrementsFn =\n          map((Integer x) -\u003e x + 1)\n          .fmap(filter(x -\u003e x % 2 == 0))\n          .fmap(reduceLeft((x, y) -\u003e x + y));\n\nMaybe\u003cInteger\u003e sumOfEvenIncrements = sumOfEvenIncrementsFn.apply(asList(1, 2, 3, 4, 5));\n//-\u003e Just 12\n```\n\nHow about the positive squares below 100:\n\n```Java\nIterable\u003cInteger\u003e positiveSquaresBelow100 =\n          takeWhile(x -\u003e x \u003c 100, map(x -\u003e x * x, iterate(x -\u003e x + 1, 1)));\n//-\u003e [1, 4, 9, 16, 25, 36, 49, 64, 81]\n```\n\nWe could have also used `unfoldr`:\n\n```Java\nIterable\u003cInteger\u003e positiveSquaresBelow100 = unfoldr(x -\u003e {\n              int square = x * x;\n              return square \u003c 100 ? Maybe.just(tuple(square, x + 1)) : Maybe.nothing();\n          }, 1);\n//-\u003e [1, 4, 9, 16, 25, 36, 49, 64, 81]\n```\n\nWhat if we want the cross product of a domain and codomain:\n\n```Java\nIterable\u003cTuple2\u003cInteger, String\u003e\u003e crossProduct =\n          take(10, cartesianProduct(asList(1, 2, 3), asList(\"a\", \"b\", \"c\")));\n//-\u003e [(1,\"a\"), (1,\"b\"), (1,\"c\"), (2,\"a\"), (2,\"b\"), (2,\"c\"), (3,\"a\"), (3,\"b\"), (3,\"c\")]\n```\n\nLet's compose two functions:\n\n```Java\nFn1\u003cInteger, Integer\u003e add = x -\u003e x + 1;\nFn1\u003cInteger, Integer\u003e subtract = x -\u003e x -1;\n\nFn1\u003cInteger, Integer\u003e noOp = add.fmap(subtract);\n// same as\nFn1\u003cInteger, Integer\u003e alsoNoOp = subtract.contraMap(add);\n```\n\nAnd partially apply some:\n\n```Java\nFn2\u003cInteger, Integer, Integer\u003e add = (x, y) -\u003e x + y;\n\nFn1\u003cInteger, Integer\u003e add1 = add.apply(1);\nadd1.apply(2);\n//-\u003e 3\n```\n\nAnd have fun with 3s:\n\n```Java\nIterable\u003cIterable\u003cInteger\u003e\u003e multiplesOf3InGroupsOf3 =\n          take(3, inGroupsOf(3, unfoldr(x -\u003e Maybe.just(tuple(x * 3, x + 1)), 1)));\n//-\u003e [[3, 6, 9], [12, 15, 18], [21, 24, 27]]\n```\n\nCheck out the [tests](https://github.com/palatable/lambda/tree/master/src/test/java/com/jnape/palatable/lambda/functions/builtin) or [javadoc](http://palatable.github.io/lambda/javadoc/) for more examples.\n\n\u003ca name=\"semigroups\"\u003eSemigroups\u003c/a\u003e\n----\n\n[Semigroups](https://en.wikipedia.org/wiki/Semigroup) are supported via `Semigroup\u003cA\u003e`, a subtype of `Fn2\u003cA,A,A\u003e`, and add left and right folds over an `Iterable\u003cA\u003e`.\n\n```Java\nSemigroup\u003cInteger\u003e add = (augend, addend) -\u003e augend + addend;\nadd.apply(1, 2); //-\u003e 3\nadd.foldLeft(0, asList(1, 2, 3)); //-\u003e 6\n```\n\nLambda ships some default logical semigroups for lambda types and core JDK types. Common examples are:\n\n- `AddAll` for concatenating two `Collection`s\n- `Collapse` for collapsing two `Tuple2`s together \n- `Merge` for merging two `Either`s using left-biasing semantics\n\nCheck out the [semigroup](https://palatable.github.io/lambda/javadoc/com/jnape/palatable/lambda/semigroup/builtin/package-summary.html) package for more examples.\n\n\u003ca name=\"monoids\"\u003eMonoids\u003c/a\u003e\n----\n\n[Monoids](https://en.wikipedia.org/wiki/Monoid) are supported via `Monoid\u003cA\u003e`, a subtype of `Semigroup\u003cA\u003e` with an `A #identity()` method, and add left and right reduces over an `Iterable\u003cA\u003e`, as well as `foldMap`.\n\n```Java\nMonoid\u003cInteger\u003e multiply = monoid((x, y) -\u003e x * y, 1);\nmultiply.reduceLeft(emptyList()); //-\u003e 1\nmultiply.reduceLeft(asList(1, 2, 3)); //-\u003e 6\nmultiply.foldMap(Integer::parseInt, asList(\"1\", \"2\", \"3\")); //-\u003e also 6\n```\n\nSome commonly used lambda monoid implementations include:\n\n- `Present` for merging together two `Optional`s\n- `Join` for joining two `String`s\n- `And` for logical conjunction of two `Boolean`s\n- `Or` for logical disjunction of two `Boolean`s\n\nAdditionally, instances of `Monoid\u003cA\u003e` can be trivially synthesized from instances of `Semigroup\u003cA\u003e` via the `Monoid#monoid` static factory method, taking the `Semigroup` and the identity element `A` or a supplier of the identity element `Supplier\u003cA\u003e`. \n\nCheck out the [monoid](https://palatable.github.io/lambda/javadoc/com/jnape/palatable/lambda/monoid/builtin/package-summary.html) package for more examples.\n\n\u003ca name=\"functors\"\u003eFunctors\u003c/a\u003e\n----\n\nFunctors are implemented via the `Functor` interface, and are sub-typed by every function type that lambda exports, as well as many of the [ADTs](#adts). \n\n```Java\npublic final class Slot\u003cA\u003e implements Functor\u003cA, Slot\u003e {\n    private final A a;\n\n    public Slot(A a) {\n        this.a = a;\n    }\n\n    public A getA() {\n        return a;\n    }\n\n    @Override\n    public \u003cB\u003e Slot\u003cB\u003e fmap(Function\u003c? super A, ? extends B\u003e fn) {\n        return new Slot\u003c\u003e(fn.apply(a));\n    }\n}\n\nSlot\u003cInteger\u003e intSlot = new Slot\u003c\u003e(1);\nSlot\u003cString\u003e stringSlot = intSlot.fmap(x -\u003e \"number: \" + x);\nstringSlot.getA(); //-\u003e \"number: 1\"\n```\n\nExamples of functors include:\n  \n- `Fn*`, `Semigroup`, and `Monoid` \n- `SingletonHList` and `Tuple*`\n- `Choice*`\n- `Either`\n- `Const`, `Identity`, and `Compose`\n- `Lens`\n\nImplementing `Functor` is as simple as providing a definition for the covariant mapping function `#fmap` (ideally satisfying the [two laws](https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Functor.html)). \n\n### \u003ca name=\"bifunctors\"\u003eBifunctors\u003c/a\u003e\n\nBifunctors -- functors that support two parameters that can be covariantly mapped over -- are implemented via the `Bifunctor` interface.\n\n```Java\npublic final class Pair\u003cA, B\u003e implements Bifunctor\u003cA, B, Pair\u003e {\n    private final A a;\n    private final B b;\n\n    public Pair(A a, B b) {\n        this.a = a;\n        this.b = b;\n    }\n\n    public A getA() {\n        return a;\n    }\n\n    public B getB() {\n        return b;\n    }\n\n    @Override\n    public \u003cC, D\u003e Pair\u003cC, D\u003e biMap(Function\u003c? super A, ? extends C\u003e lFn,\n                                   Function\u003c? super B, ? extends D\u003e rFn) {\n        return new Pair\u003c\u003e(lFn.apply(a), rFn.apply(b));\n    }\n}\n\nPair\u003cString,Integer\u003e stringIntPair = new Pair\u003c\u003e(\"str\", 1);\nPair\u003cInteger, Boolean\u003e intBooleanPair = stringIntPair.biMap(String::length, x -\u003e x % 2 == 0);\nintBooleanPair.getA(); //-\u003e 3\nintBooleanPair.getB(); //-\u003e false\n```\n\nExamples of bifunctors include:\n\n- `Tuple*`\n- `Choice*`\n- `Either`\n- `Const`\n\nImplementing `Bifunctor` requires implementing *either* `biMapL` and `biMapR` *or* `biMap`. As with `Functor`, there are a [few laws](https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Bifunctor.html) that well-behaved instances of `Bifunctor` should adhere to.\n\n### \u003ca name=\"profunctors\"\u003eProfunctors\u003c/a\u003e\n\nProfunctors -- functors that support one parameter that can be mapped over contravariantly, and a second parameter that can be mapped over covariantly -- are implemented via the `Profunctor` interface.\n\n```Java\nFn1\u003cInteger, Integer\u003e add2 = (x) -\u003e x + 2;\nadd2.\u003cString, String\u003ediMap(Integer::parseInt, Object::toString).apply(\"1\"); //-\u003e \"3\"\n```\n\nExamples of profunctors include:\n\n- `Fn*`\n- `Lens`\n\nImplementing `Profunctor` requires implementing *either* `diMapL` and `diMapR` *or* `diMap`. As with `Functor` and `Bifunctor`, there are [some laws](https://hackage.haskell.org/package/profunctors-5.2/docs/Data-Profunctor.html) that well behaved instances of `Profunctor` should adhere to.\n\n### \u003ca name=\"applicatives\"\u003eApplicatives\u003c/a\u003e\n\nApplicative functors -- functors that can be applied together with a 2-arity or higher function -- are implemented via the `Applicative` interface.\n\n```Java\npublic final class Slot\u003cA\u003e implements Applicative\u003cA, Slot\u003e {\n    private final A a;\n\n    public Slot(A a) {\n        this.a = a;\n    }\n\n    public A getA() {\n        return a;\n    }\n\n    @Override\n    public \u003cB\u003e Slot\u003cB\u003e fmap(Function\u003c? super A, ? extends B\u003e fn) {\n        return pure(fn.apply(a));\n    }\n\n    @Override\n    public \u003cB\u003e Slot\u003cB\u003e pure(B b) {\n        return new Slot\u003c\u003e(b);\n    }\n\n    @Override\n    public \u003cB\u003e Slot\u003cB\u003e zip(Applicative\u003cFunction\u003c? super A, ? extends B\u003e, Slot\u003e appFn) {\n        return pure(appFn.\u003cSlot\u003cFunction\u003c? super A, ? extends B\u003e\u003e\u003ecoerce().getA().apply(getA()));\n    }\n}\n\nFn2\u003cInteger, Integer, Integer\u003e add = (x, y) -\u003e x + y;\nSlot\u003cInteger\u003e x = new Slot\u003c\u003e(1);\nSlot\u003cInteger\u003e y = new Slot\u003c\u003e(2);\nSlot\u003cInteger\u003e z = y.zip(x.fmap(add)); //-\u003e Slot{a=3}\n```\n\nExamples of applicative functors include:\n\n- `Fn*`, `Semigroup`, and `Monoid`\n- `SingletonHList` and `Tuple*`\n- `Choice*`\n- `Either`\n- `Const`, `Identity`, and `Compose`\n- `Lens`\n\nIn addition to implementing `fmap` from `Functor`, implementing an applicative functor involves providing two methods: `pure`, a method that lifts a value into the functor; and `zip`, a method that applies a lifted function to a lifted value, returning a new lifted value. As usual, there are [some laws](https://hackage.haskell.org/package/base-4.9.1.0/docs/Control-Applicative.html) that should be adhered to. \n\n### \u003ca name=\"monads\"\u003eMonads\u003c/a\u003e\n\nMonads are applicative functors that additionally support a chaining operation, `flatMap :: (a -\u003e f b) -\u003e f a -\u003e f b`: a function from the functor's parameter to a new instance of the same functor over a potentially different parameter. Because the function passed to `flatMap` can return a different instance of the same functor, functors can take advantage of multiple constructions that yield different functorial operations, like short-circuiting, as in the following example using `Either`:\n\n```Java\nclass Person {\n    Optional\u003cOccupation\u003e occupation() {\n        return Optional.empty();\n    } \n}\n\nclass Occupation {\n}\n\npublic static void main(String[] args) {\n    Fn1\u003cString, Either\u003cString, Integer\u003e\u003e parseId = str -\u003e Either.trying(() -\u003e Integer.parseInt(str), __ -\u003e str + \" is not a valid id\"); \n\n    Map\u003cInteger, Person\u003e database = new HashMap\u003c\u003e();\n    Fn1\u003cInteger, Either\u003cString, Person\u003e\u003e lookupById = id -\u003e Either.fromOptional(Optional.ofNullable(database.get(id)),\n                                                                                () -\u003e \"No person found for id \" + id);\n    Fn1\u003cPerson, Either\u003cString, Occupation\u003e\u003e getOccupation = p -\u003e Either.fromOptional(p.occupation(), () -\u003e \"Person was unemployed\");\n\n    Either\u003cString, Occupation\u003e occupationOrError = \n        parseId.apply(\"12\") // Either\u003cString, Integer\u003e\n            .flatMap(lookupById) // Either\u003cString, Person\u003e\n            .flatMap(getOccupation); // Either\u003cString, Occupation\u003e\n}\n```\n\nIn the previous example, if any of `parseId`, `lookupById`, or `getOccupation` fail, no further `flatMap` computations can succeed, so the result short-circuits to the first `left` value that is returned. This is completely predictable from the type signature of `Monad` and `Either`: `Either\u003cL, R\u003e` is a `Monad\u003cR\u003e`, so the single arity `flatMap` can have nothing to map in the case where there is no `R` value. With experience, it generally becomes quickly clear what the logical behavior of `flatMap` *must* be given the type signatures.\n\nThat's it. Monads are neither [elephants](http://james-iry.blogspot.com/2007/09/monads-are-elephants-part-1.html) nor are they [burritos](https://blog.plover.com/prog/burritos.html); they're simply types that support a) the ability to lift a value into them, and b) a chaining function `flatMap :: (a -\u003e f b) -\u003e f a -\u003e f b` that can potentially return different instances of the same monad. If a type can do those two things (and obeys [the laws](https://wiki.haskell.org/Monad_laws)), it is a monad.\n\nFurther, if a type is a monad, it is necessarily an `Applicative`, which makes it necessarily a `Functor`, so *lambda* enforces this tautology via a hierarchical constraint.\n\n### \u003ca name=\"traversables\"\u003eTraversables\u003c/a\u003e\n\nTraversable functors -- functors that can be \"traversed from left to right\" -- are implemented via the `Traversable` interface.\n\n```Java\npublic abstract class Maybe\u003cA\u003e implements Traversable\u003cA, Maybe\u003e {\n    private Maybe() {\n    }\n\n    @Override\n    public abstract \u003cB, App extends Applicative\u003e Applicative\u003cMaybe\u003cB\u003e, App\u003e traverse(\n            Function\u003c? super A, ? extends Applicative\u003cB, App\u003e\u003e fn,\n            Function\u003c? super Traversable\u003cB, Maybe\u003e, ? extends Applicative\u003c? extends Traversable\u003cB, Maybe\u003e, App\u003e\u003e pure);\n\n    @Override\n    public abstract \u003cB\u003e Maybe\u003cB\u003e fmap(Function\u003c? super A, ? extends B\u003e fn);\n\n    private static final class Just\u003cA\u003e extends Maybe\u003cA\u003e {\n        private final A a;\n\n        private Just(A a) {\n            this.a = a;\n        }\n\n        @Override\n        public \u003cB, App extends Applicative\u003e Applicative\u003cMaybe\u003cB\u003e, App\u003e traverse(\n                Function\u003c? super A, ? extends Applicative\u003cB, App\u003e\u003e fn,\n                Function\u003c? super Traversable\u003cB, Maybe\u003e, ? extends Applicative\u003c? extends Traversable\u003cB, Maybe\u003e, App\u003e\u003e pure) {\n            return fn.apply(a).fmap(Just::new);\n        }\n\n        @Override\n        public \u003cB\u003e Maybe\u003cB\u003e fmap(Function\u003c? super A, ? extends B\u003e fn) {\n            return new Just\u003c\u003e(fn.apply(a));\n        }\n    }\n\n    private static final class Nothing\u003cA\u003e extends Maybe\u003cA\u003e {\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public \u003cB, App extends Applicative\u003e Applicative\u003cMaybe\u003cB\u003e, App\u003e traverse(\n                Function\u003c? super A, ? extends Applicative\u003cB, App\u003e\u003e fn,\n                Function\u003c? super Traversable\u003cB, Maybe\u003e, ? extends Applicative\u003c? extends Traversable\u003cB, Maybe\u003e, App\u003e\u003e pure) {\n            return pure.apply((Maybe\u003cB\u003e) this).fmap(x -\u003e (Maybe\u003cB\u003e) x);\n        }\n\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public \u003cB\u003e Maybe\u003cB\u003e fmap(Function\u003c? super A, ? extends B\u003e fn) {\n            return (Maybe\u003cB\u003e) this;\n        }\n    }\n}\n\nMaybe\u003cInteger\u003e just1 = Maybe.just(1);\nMaybe\u003cInteger\u003e nothing = Maybe.nothing();\n\nEither\u003cString, Maybe\u003cInteger\u003e\u003e traversedJust = just1.traverse(x -\u003e right(x + 1), empty -\u003e left(\"empty\"))\n        .fmap(x -\u003e (Maybe\u003cInteger\u003e) x)\n        .coerce(); //-\u003e Right(Just(2))\n\nEither\u003cString, Maybe\u003cInteger\u003e\u003e traversedNothing = nothing.traverse(x -\u003e right(x + 1), empty -\u003e left(\"empty\"))\n        .fmap(x -\u003e (Maybe\u003cInteger\u003e) x)\n        .coerce(); //-\u003e Left(\"empty\")\n```\n\nExamples of traversable functors include:\n\n- `SingletonHList` and `Tuple*`\n- `Choice*`\n- `Either`\n- `Const` and `Identity`\n- `LambdaIterable` for wrapping `Iterable` in an instance of `Traversable`\n\nIn addition to implementing `fmap` from `Functor`, implementing a traversable functor involves providing an implementation of `traverse`.\n\nAs always, there are [some laws](https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Traversable.html) that should be observed.\n\n\u003ca name=\"adts\"\u003eADTs\u003c/a\u003e\n----\n\nLambda also supports a few first-class [algebraic data types](https://www.wikiwand.com/en/Algebraic_data_type).\n\n### \u003ca name=\"maybe\"\u003eMaybe\u003c/a\u003e\n\n`Maybe` is the _lambda_ analog to `java.util.Optional`. It behaves in much of the same way as `j.u.Optional`, except that it quite intentionally does not support the inherently unsafe `j.u.Optional#get`.\n\n```Java\nMaybe\u003cInteger\u003e maybeInt = Maybe.just(1); // Just 1\nMaybe\u003cString\u003e maybeString = Maybe.nothing(); // Nothing\n```\n\nAlso, because it's a _lambda_ type, it takes advantage of the full functor hierarchy, as well as some helpful conversion functions:\n\n```Java\nMaybe\u003cString\u003e just = Maybe.maybe(\"string\"); // Just \"string\"\nMaybe\u003cString\u003e nothing = Maybe.maybe(null); // Nothing\n\nMaybe\u003cInteger\u003e maybeX = Maybe.just(1);\nMaybe\u003cInteger\u003e maybeY = Maybe.just(2);\n\nmaybeY.zip(maybeX.fmap(x -\u003e y -\u003e x + y)); // Just 3\nmaybeY.zip(nothing()); // Nothing\nMaybe.\u003cInteger\u003enothing().zip(maybeX.fmap(x -\u003e y -\u003e x + y)); // Nothing\n\nEither\u003cString, Integer\u003e right = maybeX.toEither(() -\u003e \"was empty\"); // Right 1\nEither\u003cString, Integer\u003e left = Maybe.\u003cInteger\u003enothing().toEither(() -\u003e \"was empty\"); // Left \"was empty\"\n\nMaybe.fromEither(right); // Just 1\nMaybe.fromEither(left); // Nothing\n```\n\nFinally, for compatibility purposes, `Maybe` and `j.u.Optional` can be trivially converted back and forth:\n\n```Java\nMaybe\u003cInteger\u003e just1 = Maybe.just(1); // Just 1\nOptional\u003cInteger\u003e present1 = just1.toOptional(); // Optional.of(1)\n\nOptional\u003cString\u003e empty = Optional.empty(); // Optional.empty()\nMaybe\u003cString\u003e nothing = Maybe.fromOptional(empty); // Nothing\n```\n\n***Note***: One compatibility difference between `j.u.Optional` and `Maybe` is how `map`/`fmap` behave regarding functions that return `null`: `j.u.Optional` re-wraps `null` results from `map` operations in another `j.u.Optional`, whereas `Maybe` considers this to be an error, and throws an exception. The reason `Maybe` throws in this case is because `fmap` is not an operation to be called speculatively, and so any function that returns `null` in the context of an `fmap` operation is considered to be erroneous. Instead of calling `fmap` with a function that might return `null`, the function result should be wrapped in a `Maybe` and `flatMap` should be used, as illustrated in the following example: \n\n```Java\nFunction\u003cInteger, Object\u003e nullResultFn = __ -\u003e null;\n\nOptional.of(1).map(nullResultFn); // Optional.empty()\nMaybe.just(1).fmap(nullResultFn); // throws NullPointerException\n\nMaybe.just(1).flatMap(nullResultFn.andThen(Maybe::maybe)); // Nothing\n```\n\n### \u003ca name=\"hlists\"\u003eHeterogeneous Lists (HLists)\u003c/a\u003e\n\nHLists are type-safe heterogeneous lists, meaning they can store elements of different types in the same list while facilitating certain type-safe interactions.\n\nThe following illustrates how the linear expansion of the recursive type signature for `HList` prevents ill-typed expressions:\n\n```Java\nHCons\u003cInteger, HCons\u003cString, HNil\u003e\u003e hList = HList.cons(1, HList.cons(\"foo\", HList.nil()));\n\nSystem.out.println(hList.head()); // prints 1\nSystem.out.println(hList.tail().head()); // prints \"foo\"\n\nHNil nil = hList.tail().tail();\n//nil.head() won't type-check\n```\n\n#### \u003ca name=\"tuples\"\u003eTuples\u003c/a\u003e\n\nOne of the primary downsides to using `HList`s in Java is how quickly the type signature grows.\n\nTo address this, tuples in lambda are specializations of `HList`s up to 8 elements deep, with added support for index-based accessor methods.\n\n```Java\nHNil nil = HList.nil();\nSingletonHList\u003cInteger\u003e singleton = nil.cons(8);\nTuple2\u003cInteger, Integer\u003e tuple2 = singleton.cons(7);\nTuple3\u003cInteger, Integer, Integer\u003e tuple3 = tuple2.cons(6);\nTuple4\u003cInteger, Integer, Integer, Integer\u003e tuple4 = tuple3.cons(5);\nTuple5\u003cInteger, Integer, Integer, Integer, Integer\u003e tuple5 = tuple4.cons(4);\nTuple6\u003cInteger, Integer, Integer, Integer, Integer, Integer\u003e tuple6 = tuple5.cons(3);\nTuple7\u003cInteger, Integer, Integer, Integer, Integer, Integer, Integer\u003e tuple7 = tuple6.cons(2);\nTuple8\u003cInteger, Integer, Integer, Integer, Integer, Integer, Integer, Integer\u003e tuple8 = tuple7.cons(1);\n\nSystem.out.println(tuple2._1()); // prints 7\nSystem.out.println(tuple8._8()); // prints 8\n```\n\nAdditionally, `HList` provides convenience static factory methods for directly constructing lists of up to 8 elements:\n\n```Java\nSingletonHList\u003cInteger\u003e singleton = HList.singletonHList(1);\nTuple2\u003cInteger, Integer\u003e tuple2 = HList.tuple(1, 2);\nTuple3\u003cInteger, Integer, Integer\u003e tuple3 = HList.tuple(1, 2, 3);\nTuple4\u003cInteger, Integer, Integer, Integer\u003e tuple4 = HList.tuple(1, 2, 3, 4);\nTuple5\u003cInteger, Integer, Integer, Integer, Integer\u003e tuple5 = HList.tuple(1, 2, 3, 4, 5);\nTuple6\u003cInteger, Integer, Integer, Integer, Integer, Integer\u003e tuple6 = HList.tuple(1, 2, 3, 4, 5, 6);\nTuple7\u003cInteger, Integer, Integer, Integer, Integer, Integer, Integer\u003e tuple7 = HList.tuple(1, 2, 3, 4, 5, 6, 7);\nTuple8\u003cInteger, Integer, Integer, Integer, Integer, Integer, Integer, Integer\u003e tuple8 = HList.tuple(1, 2, 3, 4, 5, 6, 7, 8);\n```\n\n`Index` can be used for type-safe retrieval and updating of elements at specific indexes:\n\n```Java\nHCons\u003cInteger, HCons\u003cString, HCons\u003cCharacter, HNil\u003e\u003e\u003e hList = cons(1, cons(\"2\", cons('3', nil())));\nHCons\u003cInteger, Tuple2\u003cString, Character\u003e\u003e tuple = tuple(1, \"2\", '3');\nTuple5\u003cInteger, String, Character, Double, Boolean\u003e longerHList = tuple(1, \"2\", '3', 4.0d, false);\n\nIndex\u003cCharacter, HCons\u003cInteger, ? extends HCons\u003cString, ? extends HCons\u003cCharacter, ?\u003e\u003e\u003e\u003e characterIndex =\n        Index.\u003cCharacter\u003eindex().\u003cString\u003eafter().after();\n\ncharacterIndex.get(hList); // '3'\ncharacterIndex.get(tuple); // '3'\ncharacterIndex.get(longerHList); // '3'\n\ncharacterIndex.set('4', hList); // HList{ 1 :: \"2\" :: '4' }\n```\n\nFinally, all `Tuple*` classes are instances of both `Functor` and `Bifunctor`:\n\n```Java\nTuple2\u003cInteger, String\u003e mappedTuple2 = tuple(1, 2).biMap(x -\u003e x + 1, Object::toString);\n\nSystem.out.println(mappedTuple2._1()); // prints 2\nSystem.out.println(mappedTuple2._2()); // prints \"2\"\n\nTuple3\u003cString, Boolean, Integer\u003e mappedTuple3 = tuple(\"foo\", true, 1).biMap(x -\u003e !x, x -\u003e x + 1);\n\nSystem.out.println(mappedTuple3._1()); // prints \"foo\"\nSystem.out.println(mappedTuple3._2()); // prints false\nSystem.out.println(mappedTuple3._3()); // prints 2\n```\n\n### \u003ca name=\"hmaps\"\u003eHeterogeneous Maps\u003c/a\u003e\n\nHMaps are type-safe heterogeneous maps, meaning they can store mappings to different value types in the same map; however, whereas HLists encode value types in their type signatures, HMaps rely on the keys to encode the value type that they point to. \n\n```Java\nTypeSafeKey\u003cString\u003e stringKey = TypeSafeKey.typeSafeKey();\nTypeSafeKey\u003cInteger\u003e intKey = TypeSafeKey.typeSafeKey();\nHMap hmap = HMap.hMap(stringKey, \"string value\",\n                      intKey, 1);\n\nOptional\u003cString\u003e stringValue = hmap.get(stringKey); // Optional[\"string value\"]\nOptional\u003cInteger\u003e intValue = hmap.get(intKey); // Optional[1]\nOptional\u003cInteger\u003e anotherIntValue = hmap.get(anotherIntKey); // Optional.empty\n```\n\n### \u003ca name=\"coproducts\"\u003eCoProducts\u003c/a\u003e\n\n`CoProduct`s generalize unions of disparate types in a single consolidated type, and the `ChoiceN` ADTs represent canonical implementations of these coproduct types.\n\n```Java\nCoProduct3\u003cString, Integer, Character, ?\u003e string = Choice3.a(\"string\");\nCoProduct3\u003cString, Integer, Character, ?\u003e integer = Choice3.b(1);\nCoProduct3\u003cString, Integer, Character, ?\u003e character = Choice3.c('a');\n```\n\nRather than supporting explicit value unwrapping, which would necessarily jeopardize type safety, `CoProduct`s support a `match` method that takes one function per possible value type and maps it to a final common result type:\n\n```Java\nCoProduct3\u003cString, Integer, Character, ?\u003e string = Choice3.a(\"string\");\nCoProduct3\u003cString, Integer, Character, ?\u003e integer = Choice3.b(1);\nCoProduct3\u003cString, Integer, Character, ?\u003e character = Choice3.c('a');\n\nInteger result = string.\u003cInteger\u003ematch(String::length, identity(), Character::charCount); // 6\n```\n\nAdditionally, because a `CoProduct2\u003cA, B, ?\u003e` guarantees a subset of a `CoProduct3\u003cA, B, C, ?\u003e`, the `diverge` method exists between `CoProduct` types of single magnitude differences to make it easy to use a more convergent `CoProduct` where a more divergent `CoProduct` is expected:\n\n```Java\nCoProduct2\u003cString, Integer, ?\u003e coProduct2 = Choice2.a(\"string\");\nCoProduct3\u003cString, Integer, Character, ?\u003e coProduct3 = coProduct2.diverge(); // still just the coProduct2 value, adapted to the coProduct3 shape\n```\n\nThere are `CoProduct` and `Choice` specializations for type unions of up to 8 different types: `CoProduct2` through `CoProduct8`, and `Choice2` through `Choice8`, respectively.\n\n### \u003ca name=\"either\"\u003eEither\u003c/a\u003e\n\n`Either\u003cL, R\u003e` represents a specialized `CoProduct2\u003cL, R\u003e`, which resolve to one of two possible values: a left value wrapping an `L`, or a right value wrapping an `R` (typically an exceptional value or a successful value, respectively).\n\nAs with `CoProduct2`, rather than supporting explicit value unwrapping, `Either` supports many useful comprehensions to help facilitate type-safe interactions:    \n\n```Java\nEither\u003cString, Integer\u003e right = Either.right(1);\nEither\u003cString, Integer\u003e left = Either.left(\"Head fell off\");\n\nInteger result = right.orElse(-1);\n//-\u003e 1\n\nList\u003cInteger\u003e values = left.match(l -\u003e Collections.emptyList(), Collections::singletonList);\n//-\u003e [] \n```\n\nCheck out the tests for [more examples](https://github.com/palatable/lambda/blob/master/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java) of ways to interact with `Either`.\n\n\u003ca name=\"lenses\"\u003eLenses\u003c/a\u003e\n----\n\nLambda also ships with a first-class \u003ca href=\"https://www.youtube.com/watch?v=cefnmjtAolY\u0026feature=youtu.be\u0026hd=1\"\u003elens\u003c/a\u003e type, as well as a small library of useful general lenses:\n\n```Java\nLens\u003cList\u003cString\u003e, List\u003cString\u003e, Optional\u003cString\u003e, String\u003e stringAt0 = ListLens.at(0);\n\nList\u003cString\u003e strings = asList(\"foo\", \"bar\", \"baz\");\nview(stringAt0, strings); // Optional[foo]\nset(stringAt0, \"quux\", strings); // [quux, bar, baz]\nover(stringAt0, s -\u003e s.map(String::toUpperCase).orElse(\"\"), strings); // [FOO, bar, baz]\n```\n\nThere are three functions that lambda provides that interface directly with lenses: `view`, `over`, and `set`. As the name implies, `view` and `set` are used to retrieve values and store values, respectively, whereas `over` is used to apply a function to the value a lens is focused on, alter it, and store it (you can think of `set` as a specialization of `over` using `constantly`).\n\nLenses can be easily created. Consider the following `Person` class:\n\n```Java\npublic final class Person {\n    private final int age;\n\n    public Person(int age) {\n        this.age = age;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public Person setAge(int age) {\n        return new Person(age);\n    }\n\n    public Person setAge(LocalDate dob) {\n        return setAge((int) YEARS.between(dob, LocalDate.now()));\n    }\n}\n```\n\n...and a lens for getting and setting `age` as an `int`:\n\n```Java\nLens\u003cPerson, Person, Integer, Integer\u003e ageLensWithInt = Lens.lens(Person::getAge, Person::setAge);\n\n//or, when each pair of type arguments match...\n\nLens.Simple\u003cPerson, Integer\u003e alsoAgeLensWithInt = Lens.simpleLens(Person::getAge, Person::setAge);\n```\n\nIf we wanted a lens for the `LocalDate` version of `setAge`, we could use the same method references and only alter the type signature:\n\n```Java\nLens\u003cPerson, Person, Integer, LocalDate\u003e ageLensWithLocalDate = Lens.lens(Person::getAge, Person::setAge);\n```\n\nCompatible lenses can be trivially composed:\n\n```Java\nLens\u003cList\u003cInteger\u003e, List\u003cInteger\u003e, Optional\u003cInteger\u003e, Integer\u003e at0 = ListLens.at(0);\nLens\u003cMap\u003cString, List\u003cInteger\u003e\u003e, Map\u003cString, List\u003cInteger\u003e\u003e, List\u003cInteger\u003e, List\u003cInteger\u003e\u003e atFoo = MapLens.atKey(\"foo\", emptyList());\n\nview(atFoo.andThen(at0), singletonMap(\"foo\", asList(1, 2, 3))); // Optional[1]\n```\n\nLens provides independent `map` operations for each parameter, so incompatible lenses can also be composed: \n\n```Java\nLens\u003cList\u003cInteger\u003e, List\u003cInteger\u003e, Optional\u003cInteger\u003e, Integer\u003e at0 = ListLens.at(0);\nLens\u003cMap\u003cString, List\u003cInteger\u003e\u003e, Map\u003cString, List\u003cInteger\u003e\u003e, Optional\u003cList\u003cInteger\u003e\u003e, List\u003cInteger\u003e\u003e atFoo = MapLens.atKey(\"foo\");\nLens\u003cMap\u003cString, List\u003cInteger\u003e\u003e, Map\u003cString, List\u003cInteger\u003e\u003e, Optional\u003cInteger\u003e, Integer\u003e composed =\n        atFoo.mapA(optL -\u003e optL.orElse(singletonList(-1)))\n                .andThen(at0);\n\nview(composed, singletonMap(\"foo\", emptyList())); // Optional.empty\n```\n\nCheck out the tests or the [javadoc](http://palatable.github.io/lambda/javadoc/) for more info.\n\n\u003ca name=\"notes\"\u003eNotes\u003c/a\u003e\n-----\n\nWherever possible, _lambda_ maintains interface compatibility with similar, familiar core Java types. Some examples of where this works well is with both `Fn1` and `Predicate`, which extend `j.u.f.Function` and `j.u.f.Predicate`, respectively. In these examples, they also override any implemented methods to return their _lambda_-specific counterparts (`Fn1.compose` returning `Fn1` instead of `j.u.f.Function` as an example).\n\nUnfortunately, due to Java's type hierarchy and inheritance inconsistencies, this is not always possible. One surprising example of this is how `Fn1` extends `j.u.f.Function`, but `Fn2` does not extend `j.u.f.BiFunction`. This is because `j.u.f.BiFunction` itself does not extend `j.u.f.Function`, but it does define methods that collide with `j.u.f.Function`. For this reason, both `Fn1` and `Fn2` cannot extend their Java counterparts without sacrificing their own inheritance hierarchy. These types of asymmetries are, unfortunately, not uncommon; however, wherever these situations arise, measures are taken to attempt to ease the transition in and out of core Java types (in the case of `Fn2`, a supplemental `#toBiFunction` method is added). I do not take these inconveniences for granted, and I'm regularly looking for ways to minimize the negative impact of this as much as possible. Suggestions and use cases that highlight particular pain points here are particularly appreciated.\n\n\u003ca name=\"ecosystem\"\u003eEcosystem\u003c/a\u003e\n-----\n\n### Official extension libraries:\n\nThese are officially supported libraries that extend lambda's core functionality and are developed under the same governance and processes as lambda.\n\n- [Shōki](https://github.com/palatable/shoki) - Purely functional, persistent data structures for the JVM\n\n### Third-party community libraries:\n\nThese are open-sourced community projects that rely on _lambda_ for significant functionality, but are not necessarily affiliated with lambda and have their own separate maintainers. If you use _lambda_ in your own open-sourced project, feel free to create an issue and I'll be happy to review the project and add it to this section!\n\n- [Enhanced Iterables](https://github.com/kschuetz/enhanced-iterables) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz)\n- [Collection Views](https://github.com/kschuetz/collection-views) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz)\n- [WuWei](https://github.com/nomicflux/WuWei) - Michael Anderson [@nomicflux](https://github.com/nomicflux) - `ST` monad for safe mutability\n- [Kraftwerk](https://github.com/kschuetz/kraftwerk) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) - random data generators and combinators\n\n\u003ca name=\"license\"\u003eLicense\u003c/a\u003e\n-------\n\n_lambda_ is part of [palatable](http://www.github.com/palatable), which is distributed under [The MIT License](http://choosealicense.com/licenses/mit/).\n","funding_links":["https://github.com/sponsors/jnape"],"categories":["Java"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalatable%2Flambda","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpalatable%2Flambda","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalatable%2Flambda/lists"}