{"id":18012875,"url":"https://github.com/tonivade/purefun","last_synced_at":"2025-04-04T10:06:41.656Z","repository":{"id":34294454,"uuid":"142195981","full_name":"tonivade/purefun","owner":"tonivade","description":"Functional Programming library for Java","archived":false,"fork":false,"pushed_at":"2025-03-28T07:06:50.000Z","size":5581,"stargazers_count":131,"open_issues_count":12,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-28T08:22:17.106Z","etag":null,"topics":["effects","experimental","free-monad","functional-programming","higher-kinded-types","immutable-collections","io-monad","java","memoization","monad","monad-transformers","monads","mtl","stream","tagless-final","tuples","typeclasses"],"latest_commit_sha":null,"homepage":"","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/tonivade.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-24T18:11:55.000Z","updated_at":"2025-03-28T07:06:47.000Z","dependencies_parsed_at":"2024-04-12T08:42:01.405Z","dependency_job_id":"2d5731fd-38d7-4b5d-927b-badc30a2be46","html_url":"https://github.com/tonivade/purefun","commit_stats":{"total_commits":1605,"total_committers":5,"mean_commits":321.0,"dds":"0.11028037383177569","last_synced_commit":"18a878f774349c70bb694a5c6f2d32e35f0ec51a"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonivade%2Fpurefun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonivade%2Fpurefun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonivade%2Fpurefun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonivade%2Fpurefun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tonivade","download_url":"https://codeload.github.com/tonivade/purefun/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247157281,"owners_count":20893220,"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":["effects","experimental","free-monad","functional-programming","higher-kinded-types","immutable-collections","io-monad","java","memoization","monad","monad-transformers","monads","mtl","stream","tagless-final","tuples","typeclasses"],"created_at":"2024-10-30T03:19:22.114Z","updated_at":"2025-04-04T10:06:41.613Z","avatar_url":"https://github.com/tonivade.png","language":"Java","readme":"# Purefun\n\n```\n ____                  __             \n|  _ \\ _   _ _ __ ___ / _|_   _ _ __  \n| |_) | | | | '__/ _ \\ |_| | | | '_ \\ \n|  __/| |_| | | |  __/  _| |_| | | | |\n|_|    \\__,_|_|  \\___|_|  \\__,_|_| |_|\n```\n\n![Build Status](https://github.com/tonivade/purefun/workflows/Java%20CI%20with%20Gradle/badge.svg)\n[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/38422db161da48f09cd192c7e7caa7dd)](https://www.codacy.com/app/zeromock/purefun?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=tonivade/purefun\u0026utm_campaign=Badge_Coverage)\n[![Join the chat at https://gitter.im/tonivade/purefun](https://badges.gitter.im/tonivade/purefun.svg)](https://gitter.im/tonivade/purefun?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nThis module was developed as the core of the zeromock project. It defines all the basic classes and interfaces\nused in the rest of the project.\n\nInitially the module only held a few basic interfaces and it has grown to become an entire\nfunctional programming library (well, a humble one), and now is an independent library.\n\nWorking in this library helped me to learn and understand some important concepts\nof functional programming, and over time I implemented higher kinded types and type classes\nin Java. I don't know if this will be helpful for somebody, but the work is here to everyone want to use it.\n\nFinally, I have to say thanks to [vavr](https://www.vavr.io/) library author, this library is largely inspired in his work,\nand also to [Scala](https://www.scala-lang.org/) standard library authors. I don't want to forget some of the projects I've used as \nreference: [Arrow](https://arrow-kt.io/) and [cats](https://typelevel.org/cats/) for type classes implementation, \n[fs2](https://fs2.io/) for stream processing, and [ZIO](https://zio.dev/) to implement my own version in Java. \nTheir awesome work help me a lot.\n\n## Disclaimer\n\n**This project is not ready to be used in production**, I use it to learn functional programming concepts by my self, but,\nif you want to use it, **use it at your own risk**. Anyway if you think is useful for you, go ahead, also any\nfeedback and PR are very welcome.\n\n## Higher Kinded Types\n\nIn this project I have implemented some patterns of functional programming that need Higher Kinded Types. In Java\nthere are not such thing, but it can be simulated using a especial codification of types.\n\nIn Scala we can define a higher kinded typed just like this `Monad[F[_]]` but in Java it can be codified\nlike this `Monad\u003cF\u003e`. Then we can define a type using a special codification like this:\n\n```java\ninterface SomeType\u003cT\u003e extends SomeTypeOf\u003cT\u003e { }\n\n// Boilerplate\ninterface SomeTypeOf\u003cT\u003e implements Kind\u003cSomeType\u003c?\u003e, T\u003e {\n\n  // this is a safe cast\n  static SomeType\u003cT\u003e toSomeType(Kind\u003cSomeType\u003c?\u003e, ? extends T\u003e hkt) {\n    return (SomeType\u003cT\u003e) hkt;\n  }\n}\n```\n\nIt can be triky but, in the end is easy to work with. By the way, I tried to hide this details to the user of the library.\nExcept with type classes because is the only way to implement them correctly.\n\nSo, there are interfaces to encode kinds of 1, 2 and 3 types. It can be defined types for 4, 5 or more types, but it wasn't\nnecessary to implement the library.\n\n## Annotation Processor\n\nIn order to simplify working with higher kinded types, in the last version I've included an annotation processor to generate\nall this boilerplate code:\n\n```java\n@HigherKind\ninterface SomeType\u003cT\u003e extends SomeTypeOf\u003cT\u003e { }\n```\n\nWith this annotation, all the above code, is generated automatically.\n\n## Data types\n\n### Option\n\nIs an alternative to `Optional` of Java standard library. It can contains two values, a `some` or a `none`\n\n```java\nOption\u003cString\u003e some = Option.some(\"Hello world\");\n\nOption\u003cString\u003e none = Option.none();\n```\n\n### Try\n\nIs an implementation of scala `Try` in Java. It can contains two values, a `success` or a `failure`.\n\n```java\nTry\u003cString\u003e success = Try.success(\"Hello world\");\n\nTry\u003cString\u003e failure = Try.failure(new RuntimeException(\"Error\"));\n```\n\n### Either\n\nIs an implementation of scala `Either` in Java.\n\n```java\nEither\u003cInteger, String\u003e right = Either.right(\"Hello world\");\n\nEither\u003cInteger, String\u003e left = Either.left(100);\n```\n\n### Validation\n\nThis type represents two different states, valid or invalid, an also it allows to combine several\nvalidations using `mapN` methods.\n\n```java\nValidation\u003cString, String\u003e name = Validation.valid(\"John Smith\");\nValidation\u003cString, String\u003e email = Validation.valid(\"john.smith@example.net\");\n\n// Person has a constructor with two String parameters, name and email.\nValdation\u003cSequence\u003cString\u003e, Person\u003e person = Validation.map2(name, email, Person::new);\n```\n\n### Const\n\nA object with a phantom parameter:\n\n```java\nConst\u003cString, Integer\u003e constInt = Const.of(\"Hello world!\");\n\nConst\u003cString, Float\u003e constFloat = constInt.retag();\n\nassertEquals(\"Hello world!\", constFloat.value());\n```\n\n### Future\n\nThis is an experimental implementation of Future. Computations are executed in another thread inmediatelly (since version 5.0 de default executor is a virtual thread per task executor).\n\n```java\nFuture\u003cString\u003e future = Future.success(\"Hello world!\");\n\nFuture\u003cString\u003e result = future.flatMap(string -\u003e Future.run(string::toUpperCase));\n\nassertEquals(Try.success(\"HELLO WORLD!\"), result.await());\n```\n\n### Trampoline\n\nImplements recursion using an iteration and is stack safe.\n\n```java\nprivate Trampoline\u003cInteger\u003e fibLoop(Integer n) {\n  if (n \u003c 2) {\n    return Trampoline.done(n);\n  }\n  return Trampoline.more(() -\u003e fibLoop(n - 1)).flatMap(x -\u003e fibLoop(n - 2).map(y -\u003e x + y));\n}\n```\n\n### Tuples\n\nThese classes allow to hold some values together, as tuples. There are tuples from 1 to 5.\n\n```java\nTuple1\u003cString\u003e tuple1 = Tuple.of(\"Hello world\");\n\nTuple2\u003cString, Integer\u003e tuple2 = Tuple.of(\"John Smith\", 100);\n```\n\n## Data structures\n\nJava doesn't define immutable collections, so I have implemented some of them.\n\n### Sequence\n\nIs the equivalent to java `Collection` interface. It defines all the common methods. The default implementation use persistent collections based on [pcollections](https://github.com/hrldcpr/pcollections/) library.\n\n### ImmutableList\n\nIt represents a linked list. It has a head and a tail. Based on `ConsPStack`.\n\n### ImmutableSet\n\nIt represents a set of elements. This elements cannot be duplicated. Based on `HashTreePSet`.\n\n### ImmutableArray\n\nIt represents an array. You can access to the elements by its position in the array. Based on `TreePVector`.\n\n### ImmutableMap\n\nThis class represents a hash map. Based on `HashTreePMap`.\n\n### ImmutableTree\n\nThis class represents a binary tree. Based on `TreePSet`\n\n### ImmutableTreeMap\n\nThis class represents a binary tree map. Based on `TreePMap`.\n\n## Monads\n\nAlso I have implemented some Monads that allows to combine some operations.\n\n### State Monad\n\nIs the traditional State Modad from FP languages, like Haskel or Scala. It allows to combine\noperations over a state. The state should be a immutable class. It recives an state and generates\na tuple with the new state and an intermediate result.\n\n```java\nState\u003cImmutableList\u003cString\u003e, Option\u003cString\u003e\u003e read = State.state(list -\u003e Tuple.of(list.tail(), list.head()));\n\nTuple\u003cImmutableList\u003cString\u003e, Option\u003cString\u003e\u003e result = read.run(ImmutableList.of(\"a\", \"b\", \"c\"));\n\nassertEquals(Tuple.of(ImmutableList.of(\"b\", \"c\"), Option.some(\"a\")), result);\n```\n\n### Reader Monad\n\nThis is an implementation of Reader Monad. It allows to combine operations over a common input.\nIt can be used to inject dependencies.\n\n```java\nReader\u003cImmutableList\u003cString\u003e, String\u003e read2 = Reader.reader(list -\u003e list.tail().head().orElse(\"\"));\n\nString result = read2.eval(ImmutableList.of(\"a\", \"b\", \"c\"));\n\nassertEqual(\"b\", result);\n```\n\n### Writer Monad\n\nIt allow to combine operations over a common output.\n\n```java\nWriter\u003cImmutableList\u003cString\u003e, Integer\u003e writer = Writer.\u003cString, Integer\u003elistPure(5)\n    .flatMap(value -\u003e listWriter(\"add 5\", value + 5))\n    .flatMap(value -\u003e listWriter(\"plus 2\", value * 2));\n\nassertAll(() -\u003e assertEquals(Integer.valueOf(20), writer.getValue()),\n          () -\u003e assertEquals(listOf(\"add 5\", \"plus 2\"), writer.getLog()));\n```\n\n### IO Monad\n\nThis is a experimental implementation of IO Monad in java. Inspired in this [work](https://gist.github.com/joergrathlev/f17092d3470dcf732be6).\n\n```java\nIO\u003cUnit\u003e echo = Console.print(\"write your name\")\n  .andThen(Console.read())\n  .flatMap(name -\u003e Console.print(\"Hello \" + name))\n  .andThen(Console.print(\"end\"));\n\necho.unsafeRunSync();\n```\n\n## Free\n\n### Free Monad\n\nFinally, after hours of hard coding, I managed to implement a Free monad. This is a highly\nunstable implementation and I have implemented because it can be implemented. Inspired\nin this [work](https://github.com/xuwei-k/free-monad-java).\n\n```java\nFree\u003cIOProgram_, Unit\u003e echo =\n  IOProgram.write(\"what's your name?\")\n    .andThen(IOProgram.read())\n    .flatMap(text -\u003e IOProgram.write(\"Hello \" + text))\n    .andThen(IOProgram.write(\"end\"));\n\nKind\u003cIO_, Unit\u003e foldMap = echo.foldMap(IOInstances.monad(), new IOProgramInterperter());\n\nfoldMap.fix(toIO()).unsafeRunSync();\n```\n\n### Free Applicative\n\nSimilar to Free monad, but allows static analysis without to run the program.\n\n```java\nFreeAp\u003cDSL_, Tuple5\u003cInteger, Boolean, Double, String, Unit\u003e\u003e tuple =\n    applicative.map5(\n        DSL.readInt(2),\n        DSL.readBoolean(false),\n        DSL.readDouble(2.1),\n        DSL.readString(\"hola mundo\"),\n        DSL.readUnit(),\n        Tuple::of\n    ).fix(toFreeAp());\n\nKind\u003cId_, Tuple5\u003cInteger, Boolean, Double, String, Unit\u003e\u003e map =\n    tuple.foldMap(idTransform(), IdInstances.applicative());\n\nassertEquals(Id.of(Tuple.of(2, false, 2.1, \"hola mundo\", unit())), map.fix(toId()));\n```\n\n## Monad Transformers\n\n### OptionT\n\nMonad Transformer for `Option` type\n\n```java\nOptionT\u003cIO_, String\u003e some = OptionT.some(IO.monad(), \"abc\");\n\nOptionT\u003cIO_, String\u003e map = some.flatMap(value -\u003e OptionT.some(IOInstances.monad(), value.toUpperCase()));\n\nassertEquals(\"ABC\", map.get().fix(toIO()).unsafeRunSync());\n```\n\n### EitherT\n\nMonad Transformer for `Either` type\n\n```java\nEitherT\u003cIO_, Nothing, String\u003e right = EitherT.right(IO.monad(), \"abc\");\n\nEitherT\u003cIO_, Nothing, String\u003e map = right.flatMap(value -\u003e EitherT.right(IOInstances.monad(), value.toUpperCase()));\n\nassertEquals(\"ABC\", map.get().fix(toIO()).unsafeRunSync());\n```\n\n### StateT\n\nMonad Transformer for `State` type\n\n```java\nStateT\u003cIO_, ImmutableList\u003cString\u003e, Unit\u003e state =\n  pure(\"a\").flatMap(append(\"b\")).flatMap(append(\"c\")).flatMap(end());\n\nIO\u003cTuple2\u003cImmutableList\u003cString\u003e, Unit\u003e\u003e result = state.run(ImmutableList.empty()).fix(toIO());\n\nassertEquals(Tuple.of(listOf(\"a\", \"b\", \"c\"), unit()), result.unsafeRunSync());\n```\n\n### WriterT\n\nMonad Transformer for `Writer` type\n\n```java\nWriterT\u003cId_, Sequence\u003cString\u003e, Integer\u003e writer =\n    WriterT.\u003cId_, Sequence\u003cString\u003e, Integer\u003epure(monoid, monad, 5)\n    .flatMap(value -\u003e lift(monoid, monad, Tuple.of(listOf(\"add 5\"), value + 5)))\n    .flatMap(value -\u003e lift(monoid, monad, Tuple.of(listOf(\"plus 2\"), value * 2)));\n\nassertAll(() -\u003e assertEquals(Id.of(Integer.valueOf(20)), writer.getValue()),\n          () -\u003e assertEquals(Id.of(listOf(\"add 5\", \"plus 2\")), writer.getLog()));\n```\n\n### Kleisli\n\nAlso I implemented the Kleisli composition for functions that returns monadic values like `Option`, `Try` or `Either`.\n\n```java\nKleisli\u003cTry_, String, Integer\u003e toInt = Kleisli.lift(Try.monad(), Integer::parseInt);\nKleisli\u003cTry_, Integer, Double\u003e half = Kleisli.lift(Try.monad(), i -\u003e i / 2.);\n\nKind\u003cTry_, Double\u003e result = toInt.compose(half).run(\"123\");\n\nassertEquals(Try.success(61.5), result);\n```\n\n## Stream\n\nAn experimental version of a `Stream` like scala fs2 project.\n\n```java\nStreamOf\u003cIO\u003c?\u003e\u003e streamOfIO = Stream.ofIO();\n\nIO\u003cString\u003e readFile = streamOfIO.eval(IO.of(() -\u003e reader(file)))\n  .flatMap(reader -\u003e streamOfIO.iterate(() -\u003e Option.of(() -\u003e readLine(reader))))\n  .takeWhile(Option::isPresent)\n  .map(Option::get)\n  .foldLeft(\"\", (a, b) -\u003e a + \"\\n\" + b)\n  .fix(IOOf::toIO)\n  .recoverWith(UncheckedIOException.class, cons(\"--- file not found ---\"));\n\nString content = readFile.unsafeRunSync();\n```\n\n## Effects\n\nAn experimental version of `PureIO` similar to ZIO.\n\n```java\nPureIO\u003cConsole, Throwable, Unit\u003e echoProgram =\n  Console.println(\"what's your name?\")\n      .andThen(Console.readln())\n      .flatMap(name -\u003e Console.println(\"Hello \" + name));\n\ninterface Console {\n\n  \u003cR extends Console\u003e Console.Service\u003cR\u003e console();\n\n  static PureIO\u003cConsole, Throwable, String\u003e readln() {\n    return PureIO.accessM(env -\u003e env.console().readln());\n  }\n\n  static PureIO\u003cConsole, Throwable, Unit\u003e println(String text) {\n    return PureIO.accessM(env -\u003e env.console().println(text));\n  }\n\n  interface Service\u003cR extends Console\u003e {\n    PureIO\u003cR, Throwable, String\u003e readln();\n\n    PureIO\u003cR, Throwable, Unit\u003e println(String text);\n  }\n}\n```\n\nAdditionally, there are aliases for some PureIO special cases:\n\n```\nUIO\u003cT\u003e      =\u003e  PureIO\u003cVoid, Void, T\u003e\nEIO\u003cE, T\u003e   =\u003e  PureIO\u003cVoid, E, T\u003e\nTask\u003cT\u003e     =\u003e  PureIO\u003cVoid, Throwable, T\u003e\nRIO\u003cR, T\u003e   =\u003e  PureIO\u003cR, Throwable, T\u003e\nURIO\u003cT\u003e     =\u003e  PureIO\u003cR, Void, T\u003e\n```\n\n## Type Classes\n\nWith higher kinded types simulation we can implement typeclases.\n\n```\n                       Invariant -- Contravariant\n                             \\\n       SemigroupK           Functor -- Comonad\n           |               /       \\\n         MonoidK   _ Applicative   Traverse -- Foldable\n           |      /      |      \\\n       Alternative    Selective  ApplicativeError\n                         |        |\n  MonadWriter          Monad      |\n        \\________________|        |\n        /          /      \\      / \n  MonadState  MonadReader  MonadError_____\n                               \\          \\\n                            MonadThrow  Bracket\n                                  \\      /\n                        Defer -- MonadDefer -- Timer\n                                     |\n                                   Async\n                                     |\n                                 Concurrent\n```\n\n### Functor\n\n```java\npublic interface Functor\u003cF extends \u003e extends Invariant\u003cF\u003e {\n\n  \u003cT, R\u003e Kind\u003cF, R\u003e map(Kind\u003cF, T\u003e value, Function1\u003cT, R\u003e map);\n}\n```\n\n### Applicative\n\n```java\npublic interface Applicative\u003cF\u003e extends Functor\u003cF\u003e {\n\n  \u003cT\u003e Kind\u003cF, T\u003e pure(T value);\n\n  \u003cT, R\u003e Kind\u003cF, R\u003e ap(Kind\u003cF, T\u003e value, Kind\u003cF, Function1\u003cT, R\u003e\u003e apply);\n\n  @Override\n  default \u003cT, R\u003e Kind\u003cF, R\u003e map(Kind\u003cF, T\u003e value, Function1\u003cT, R\u003e map) {\n    return ap(value, pure(map));\n  }\n}\n```\n\n### Selective\n\n```java\npublic interface Selective\u003cF\u003e extends Applicative\u003cF\u003e {\n\n  \u003cA, B\u003e Kind\u003cF, B\u003e select(Kind\u003cF, Either\u003cA, B\u003e\u003e value, Kind\u003cF, Function1\u003cA, B\u003e\u003e apply);\n\n  default \u003cA, B, C\u003e Kind\u003cF, C\u003e branch(Kind\u003cF, Either\u003cA, B\u003e\u003e value,\n                                      Kind\u003cF, Function1\u003cA, C\u003e\u003e applyA,\n                                      Kind\u003cF, Function1\u003cB, C\u003e\u003e applyB) {\n    Kind\u003cF, Either\u003cA, Either\u003cB, C\u003e\u003e\u003e abc = map(value, either -\u003e either.map(Either::left));\n    Kind\u003cF, Function1\u003cA, Either\u003cB, C\u003e\u003e\u003e fabc = map(applyA, fb -\u003e fb.andThen(Either::right));\n    return select(select(abc, fabc), applyB);\n  }\n}\n```\n\n### Monad\n\n```java\npublic interface Monad\u003cF\u003e extends Selective\u003cF\u003e {\n\n  \u003cT, R\u003e Kind\u003cF, R\u003e flatMap(Kind\u003cF, T\u003e value, Function1\u003cT, ? extends Kind\u003cF, R\u003e\u003e map);\n\n  @Override\n  default \u003cT, R\u003e Kind\u003cF, R\u003e map(Kind\u003cF, T\u003e value, Function1\u003cT, R\u003e map) {\n    return flatMap(value, map.andThen(this::pure));\n  }\n\n  @Override\n  default \u003cT, R\u003e Kind\u003cF, R\u003e ap(Kind\u003cF, T\u003e value, Kind\u003cF, Function1\u003cT, R\u003e\u003e apply) {\n    return flatMap(apply, map -\u003e map(value, map));\n  }\n\n  @Override\n  default \u003cA, B\u003e Kind\u003cF, B\u003e select(Kind\u003cF, Either\u003cA, B\u003e\u003e value, Kind\u003cF, Function1\u003cA, B\u003e\u003e apply) {\n    return flatMap(value, either -\u003e either.fold(a -\u003e map(apply, map -\u003e map.apply(a)), this::\u003cB\u003epure));\n  }\n}\n```\n\n### Semigroup\n\nIt represents a binary operation over a type.\n\n```java\n@FunctionalInterface\npublic interface Semigroup\u003cT\u003e {\n  T combine(T t1, T t2);\n}\n```\n\nThere are instances for strings and integers.\n\n### Monoid\n\nExtends `Semigroup` adding a `zero` operation that represent an identity.\n\n```java\npublic interface Monoid\u003cT\u003e extends Semigroup\u003cT\u003e {\n  T zero();\n}\n```\n\nThere are instances for strings and integers.\n\n### SemigroupK\n\nIt represents a `Semigroup` but defined for a kind, like a List, so it extends a regular `Semigroup`.\n\n### MonoidK\n\nThe same like `SemigroupK` but for a `Monoid`.\n\n### Invariant\n\n```java\npublic interface Invariant\u003cF\u003e {\n  \u003cA, B\u003e Kind\u003cF, B\u003e imap(Kind\u003cF, A\u003e value, Function1\u003cA, B\u003e map, Function1\u003cB, A\u003e comap);\n}\n```\n\n### Contravariant\n\n```java\npublic interface Contravariant\u003cF\u003e extends Invariant\u003cF\u003e {\n  \u003cA, B\u003e Kind\u003cF, B\u003e contramap(Kind\u003cF, A\u003e value, Function1\u003cB, A\u003e map);\n}\n```\n\n### Applicative Error\n\n```java\npublic interface ApplicativeError\u003cF, E\u003e extends Applicative\u003cF\u003e {\n\n  \u003cA\u003e Kind\u003cF, A\u003e raiseError(E error);\n\n  \u003cA\u003e Kind\u003cF, A\u003e handleErrorWith(Kind\u003cF, A\u003e value, Function1\u003cE, ? extends Kind\u003cF, A\u003e\u003e handler);\n}\n```\n\n### Monad Error\n\n```java\npublic interface MonadError\u003cF, E\u003e extends ApplicativeError\u003cF, E\u003e, Monad\u003cF\u003e {\n\n  default \u003cA\u003e Kind\u003cF, A\u003e ensure(Kind\u003cF, A\u003e value, Producer\u003cE\u003e error, Matcher1\u003cA\u003e matcher) {\n    return flatMap(value, a -\u003e matcher.match(a) ? pure(a) : raiseError(error.get()));\n  }\n}\n```\n\n### Monad Throw\n\n```java\npublic interface MonadThrow\u003cF\u003e extends MonadError\u003cF, Throwable\u003e {\n\n}\n```\n\n### MonadReader\n\n```java\npublic interface MonadReader\u003cF, R\u003e extends Monad\u003cF\u003e {\n\n  Kind\u003cF, R\u003e ask();\n\n  default \u003cA\u003e Kind\u003cF, A\u003e reader(Function1\u003cR, A\u003e mapper) {\n    return map(ask(), mapper);\n  }\n}\n```\n\n### MonadState\n\n```java\npublic interface MonadState\u003cF, S\u003e extends Monad\u003cF\u003e {\n  Kind\u003cF, S\u003e get();\n  Kind\u003cF, Unit\u003e set(S state);\n\n  default Kind\u003cF, Unit\u003e modify(Operator1\u003cS\u003e mapper) {\n    return flatMap(get(), s -\u003e set(mapper.apply(s)));\n  }\n\n  default \u003cA\u003e Kind\u003cF, A\u003e inspect(Function1\u003cS, A\u003e mapper) {\n    return map(get(), mapper);\n  }\n\n  default \u003cA\u003e Kind\u003cF, A\u003e state(Function1\u003cS, Tuple2\u003cS, A\u003e\u003e mapper) {\n    return flatMap(get(), s -\u003e mapper.apply(s).applyTo((s1, a) -\u003e map(set(s1), x -\u003e a)));\n  }\n}\n```\n\n### MonadWriter\n\n```java\npublic interface MonadWriter\u003cF, W\u003e extends Monad\u003cF\u003e {\n\n  \u003cA\u003e Kind\u003cF, A\u003e writer(Tuple2\u003cW, A\u003e value);\n  \u003cA\u003e Kind\u003cF, Tuple2\u003cW, A\u003e\u003e listen(Kind\u003cF, A\u003e value);\n  \u003cA\u003e Kind\u003cF, A\u003e pass(Kind\u003cF, Tuple2\u003cOperator1\u003cW\u003e, A\u003e\u003e value);\n\n  default Kind\u003cF, Unit\u003e tell(W writer) {\n    return writer(Tuple.of(writer, unit()));\n  }\n}\n```\n\n### Comonad\n\n```java\npublic interface Comonad\u003cF\u003e extends Functor\u003cF\u003e {\n\n  \u003cA, B\u003e Kind\u003cF, B\u003e coflatMap(Kind\u003cF, A\u003e value, Function1\u003cKind\u003cF, A\u003e, B\u003e map);\n\n  \u003cA\u003e A extract(Kind\u003cF, A\u003e value);\n\n  default \u003cA\u003e Kind\u003cF, Kind\u003cF, A\u003e\u003e coflatten(Kind\u003cF, A\u003e value) {\n    return coflatMap(value, identity());\n  }\n}\n```\n\n### Foldable\n\n```java\npublic interface Foldable\u003cF\u003e {\n\n  \u003cA, B\u003e B foldLeft(Kind\u003cF, A\u003e value, B initial, Function2\u003cB, A, B\u003e mapper);\n\n  \u003cA, B\u003e Eval\u003cB\u003e foldRight(Kind\u003cF, A\u003e value, Eval\u003cB\u003e initial, Function2\u003cA, Eval\u003cB\u003e, Eval\u003cB\u003e\u003e mapper);\n}\n```\n\n### Traverse\n\n```java\npublic interface Traverse\u003cF\u003e extends Functor\u003cF\u003e, Foldable\u003cF\u003e {\n\n  \u003cG, T, R\u003e Kind\u003cG, Kind\u003cF, R\u003e\u003e traverse(Applicative\u003cG\u003e applicative, Kind\u003cF, T\u003e value,\n      Function1\u003cT, ? extends Kind\u003cG, R\u003e\u003e mapper);\n}\n```\n\n### Semigroupal\n\n```java\npublic interface Semigroupal\u003cF\u003e {\n\n  \u003cA, B\u003e Kind\u003cF, Tuple2\u003cA, B\u003e\u003e product(Kind\u003cF, A\u003e fa, Kind\u003cF, B\u003e fb);\n}\n```\n\n### Defer\n\n```java\npublic interface Defer\u003cF\u003e {\n\n  \u003cA\u003e Kind\u003cF, A\u003e defer(Producer\u003cKind\u003cF, A\u003e\u003e defer);\n}\n```\n\n### Bracket\n\n```java\npublic interface Bracket\u003cF, E\u003e extends MonadError\u003cF, E\u003e {\n\n  \u003cA, B\u003e Kind\u003cF, B\u003e bracket(Kind\u003cF, A\u003e acquire, Function1\u003cA, ? extends Kind\u003cF, B\u003e\u003e use, Consumer1\u003cA\u003e release);\n}\n```\n\n### MonadDefer\n\n```java\npublic interface MonadDefer\u003cF\u003e extends MonadThrow\u003cF\u003e, Bracket\u003cF, Throwable\u003e, Defer\u003cF\u003e, Timer\u003cF\u003e {\n\n  default \u003cA\u003e Kind\u003cF, A\u003e later(Producer\u003cA\u003e later) {\n    return defer(() -\u003e Try.of(later::get).fold(this::raiseError, this::pure));\n  }\n}\n```\n\n### Async\n\n```java\npublic interface Async\u003cF\u003e extends MonadDefer\u003cF\u003e {\n  \n  \u003cA\u003e Kind\u003cF, A\u003e async(Consumer1\u003cConsumer1\u003cTry\u003cA\u003e\u003e\u003e consumer);\n\n}\n```\n\n### Timer\n\n```java\npublic interface Timer\u003cF\u003e {\n\n  Kind\u003cF, Unit\u003e sleep(Duration duration);\n}\n```\n\n### FunctionK\n\nIt represents a natural transformation between two different kinds.\n\n```java\npublic interface FunctionK\u003cF, G\u003e {\n  \u003cT\u003e Kind\u003cG, T\u003e apply(Kind\u003cF, T\u003e from);\n}\n```\n\n## Optics\n\n```\n         __Iso__\n        /       \\\n    Lens        Prism\n        \\       /\n         Optional\n```\n\n### Iso\n\nAn `Iso` is an optic which converts elements of some type into elements of other type without loss.\nIn other words, it's **isomorphic**.\n\n```java\nPoint point = new Point(1, 2);\n\nIso\u003cPoint, Tuple2\u003cInteger, Integer\u003e\u003e pointToTuple = \n  Iso.of(p -\u003e Tuple.of(p.x, p.y), \n         t -\u003e new Point(t.get1(), t.get2()));\n\nassertEquals(point, pointToTuple.set(pointToTuple.get(point)));\n```\n\n### Lens\n\nA `Lens` is an optic used to zoom inside a structure. In other words, it's an abstraction of a setter and a getter \nbut with immutable objects.\n\n```java\nLens\u003cEmployee, String\u003e nameLens = Lens.of(Employee::getName, Employee::withName);\n\nEmployee pepe = new Employee(\"pepe\");\n\nassertEquals(\"pepe\", nameLens.get(pepe));\nassertEquals(\"paco\", nameLens.get(nameLens.set(pepe, \"paco\")));\n```\n\nWe can compose Lenses to get deeper inside. For example, if we add an attribute of type `Address` into `Employee`.\nWe can create a lens to access the city name of the address of the employee.\n\n```java\nLens\u003cEmployee, Address\u003e addressLens = Lens.of(Employee::getAddress, Employee::withAddress);\nLens\u003cAddress, String\u003e cityLens = Lens.of(Address::getCity, Address::withCity);\nLens\u003cEmployee, String\u003e cityAddressLens = addressLens.compose(cityLens);\n\nEmployee pepe = new Employee(\"pepe\", new Address(\"Madrid\"));\n\nassertEquals(\"Madrid\", cityAddressLens.get(pepe));\n```\n\n### Prism\n\nA `Prism` is a lossless invertible optic that can see into a structure and optionally find a value. \n\n```java\nFunction1\u003cString, Option\u003cInteger\u003e\u003e parseInt = ...; // is a method that only returns a value when the string can be parsed\n\nPrism\u003cString, Integer\u003e stringToInteger = Prism.of(parseInt, String::valueOf);\n\nassertEquals(Option.some(5), stringToInteger.getOption(\"5\"));\nassertEquals(Option.none(), stringToInteger.getOption(\"a\"));\nassertEquals(\"5\", stringToInteger.reverseGet(5));\n```\n\n### Optional\n\nAn `Optional` is an optic that allows to see into a structure and getting, setting like a `Lens` an optional find a value like a `Prism`.\n\n```java\nOptional\u003cEmployee, Address\u003e addressOptional = Optional.of(\n  Employee::withAddress, employee -\u003e Option.of(employee::getAddress)\n);\n\nAddress madrid = new Address(\"Madrid\");\nEmployee pepe = new Employee(\"pepe\", null);\n\nassertEquals(Option.none(), addressOptional.getOption(pepe));\nassertEquals(Option.some(madrid), addressOptional.getOption(addressOptional.set(pepe, madrid)));\n```\n\n### Composition\n\n|  | Optional | Prism | Lens | Iso |\n|------|------|-------|-------|-------|\n| Optional | Optional | Optional | Optional | Optional |\n| Prism | Optional | Prism | Optional | Prism |\n| Lens | Optional | Optional | Lens | Lens |\n| Iso | Optional | Prism | Lens | Iso |\n\n## Equal\n\nThis class helps to create readable `equals` methods. An example:\n\n```java\n@Override\npublic boolean equals(Object obj) {\n  return Equal.\u003cData\u003eof()\n    .comparing(Data::getId)\n    .comparing(Data::getValue)\n    .applyTo(this, obj);\n}\n```\n\n## Stargazers over time\n\n[![Stargazers over time](https://starchart.cc/tonivade/purefun.svg)](https://starchart.cc/tonivade/purefun)\n\n## License\n\npurefun is released under MIT license\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonivade%2Fpurefun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftonivade%2Fpurefun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonivade%2Fpurefun/lists"}