{"id":13485826,"url":"https://github.com/derive4j/derive4j","last_synced_at":"2025-04-12T14:55:28.314Z","repository":{"id":41474459,"uuid":"42741668","full_name":"derive4j/derive4j","owner":"derive4j","description":"Java 8 annotation processor and framework for deriving algebraic data types constructors, pattern-matching, folds, optics and typeclasses.","archived":false,"fork":false,"pushed_at":"2022-12-01T03:28:00.000Z","size":1046,"stargazers_count":570,"open_issues_count":18,"forks_count":49,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-04-03T13:18:32.817Z","etag":null,"topics":["algebra","algebraic-data-types","annotation-processor","catamorphisms","derive4j","discriminated-unions","exhaustiveness-checking","fold","functional-programming","java","java-8","laziness","optics","sum-types","tagged-unions","visitor","visitor-pattern"],"latest_commit_sha":null,"homepage":"","language":"Java","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/derive4j.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSES","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-09-18T18:59:34.000Z","updated_at":"2025-03-10T15:23:44.000Z","dependencies_parsed_at":"2023-01-23T12:00:51.795Z","dependency_job_id":null,"html_url":"https://github.com/derive4j/derive4j","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derive4j%2Fderive4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derive4j%2Fderive4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derive4j%2Fderive4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derive4j%2Fderive4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/derive4j","download_url":"https://codeload.github.com/derive4j/derive4j/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248586243,"owners_count":21128995,"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":["algebra","algebraic-data-types","annotation-processor","catamorphisms","derive4j","discriminated-unions","exhaustiveness-checking","fold","functional-programming","java","java-8","laziness","optics","sum-types","tagged-unions","visitor","visitor-pattern"],"created_at":"2024-07-31T18:00:32.149Z","updated_at":"2025-04-12T14:55:28.287Z","avatar_url":"https://github.com/derive4j.png","language":"Java","readme":"# Derive4J: Java 8 annotation processor for deriving algebraic data types constructors, pattern matching and more!\n\n[![Travis](https://travis-ci.org/derive4j/derive4j.svg?branch=master)](https://travis-ci.org/derive4j/derive4j)\n[![codecov.io](https://codecov.io/github/derive4j/derive4j/branch/master/graph/badge.svg)](https://codecov.io/github/derive4j/derive4j)\n[![Maven Central](https://img.shields.io/maven-central/v/org.derive4j/derive4j.svg)][search.maven]\n[![Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/derive4j/derive4j)\n\n**tl;dr** [Show me how to write, say, the `Either` sum type with Derive4J!](https://gist.github.com/jbgi/d6035910e55b5b45d1e18553530d9d72).\n\n## Table of contents\n- [Example: a 'Visitor' for HTTP Request](#example-a-visitor-for-http-request)\n    - [Constructors](#constructors)  \n    - [equals, hashCode, toString?](#equals-hashcode-tostring)  \n    - [Pattern matching syntaxes](#pattern-matching-syntaxes)\n    - [Accessors (getters)](#accessors-getters)\n    - [Functional setters ('withers')](#functional-setters-withers)\n    - [First class laziness](#first-class-laziness)\n    - [Flavours](#flavours)\n    - [Optics (functional lenses)](#optics-functional-lenses)\n- [Smart constructors](#smart-constructors)\n- [Static methods export](#static-methods-export)\n- [Updating deeply nested immutable data structure](#updating-deeply-nested-immutable-data-structure)\n- [Popular use-case: domain specific languages](#popular-use-case-domain-specific-languages)\n- [Catamorphisms](#catamorphisms)\n- [Extensible algebraic data types](#extensible-algebraic-data-types)\n- [But what exactly is generated?](#but-what-exactly-is-generated)\n- [Parametric polymorphism](#parametric-polymorphism)\n- [Generalized Algebraic Data Types](#generalized-algebraic-data-types)\n- [DRY annotation configuration](#dry-annotation-configuration)\n- [Use it in your project](#use-it-in-your-project)\n- [Changelog](https://github.com/derive4j/derive4j/milestones?state=closed)\n- [Contributing](#contributing)\n- [Contact](#contact)\n\n**Caution**: if you are not familiar with Algebraic Data Types or the \"visitor pattern\" then you may want to [learn a bit about them](#further-reading).\n\nSo, what can this project do for us, poor functional programmers stuck with a legacy language called Java?\nA good deal of what is commonly available in better languages like Haskell, including:\n - structural pattern matching on Algebraic data types, with compile-time exhaustiveness/redundancy check,\n - laziness (a value can be a memoized [thunk](https://wiki.haskell.org/Thunk)),\n - [automatic type class derivation](https://github.com/derive4j/derive4j-fj)\n - [Generalised algebraic data types](https://wiki.haskell.org/GADT)\n - combinators implementing [lenses](http://julien-truffaut.github.io/Monocle/optics/lens.html), [prisms](http://julien-truffaut.github.io/Monocle/optics/prism.html) and [optionals](http://julien-truffaut.github.io/Monocle/optics/optional.html).\n\nAlgebraic data types come in two flavours, product types and sum types. This readme focus on sum types because it is the more interesting case; product types being the well known common case in Java, but Derive4J handles product types in exactly the same fashion (ie. through a visitor interface with a single abstract method).\n\n# Example: a 'Visitor' for HTTP Request\n\nLet's say we want to model an HTTP request. For the sake of the example let's say that an HTTP request can either be\n- a GET on a given ```path```\n- a DELETE on a given ```path```\n- a POST of a content ```body``` on a given ```path```\n- a PUT of a content ```body``` on a given ```path```\n\nand nothing else!\n\nYou could then use the [corrected visitor pattern](http://logji.blogspot.ch/2012/02/correcting-visitor-pattern.html) and write the following class in Java:\n\n```java\npackage org.derive4j.example;\n\n/** A data type to model an http request. */\n@Data\npublic abstract class Request {\n\n  /** the Request 'visitor' interface, R being the return type\n   *  used by the 'accept' method : */\n  interface Cases\u003cR\u003e {\n    // A request can either be a 'GET' (of a path):\n    R GET(String path);\n    // or a 'DELETE' (of a path):\n    R DELETE(String path);\n    // or a 'PUT' (on a path, with a body):\n    R PUT(String path, String body);\n    // or a 'POST' (on a path, with a body):\n    R POST(String path, String body);\n    // and nothing else!\n  }\n\n  // the 'accept' method of the visitor pattern:\n  public abstract \u003cR\u003e R match(Cases\u003cR\u003e cases);\n\n  /**\n   * Alternatively and equivalently to the visitor pattern above, if you prefer a more FP style,\n   * you can define a catamorphism instead. (see examples)\n   * (most useful for standard data type like Option, Either, List...)\n   */\n}\n```\n## Constructors\n\nWithout Derive4J, you would have to create subclasses of ```Request``` for all four cases. That is, write at the minimum something like:\n```java\n  public static Request GET(String path) {\n    return new Request() {\n      @Override\n      public \u003cR\u003e R match(Cases\u003cR\u003e cases) {\n        return cases.GET(path);\n      }\n    };}\n```\nfor each case.\nBut thanks to the ```@Data``` annotation, Derive4j will do that for you! That is, it will generate a ```Requests``` class (the name is configurable, the class is generated by default in ```target/generated-sources/annotations``` when using Maven) with four static factory methods (what we call '*constructors*' in FP):\n```java\n  public static Request GET(String path) {...}\n  public static Request DELETE(String path) {...}\n  public static Request PUT(String path, String body) {...}\n  public static Request POST(String path, String body) {...}\n```\nYou can also ask Derive4J to generate null checks with: \n```java\n@Data(arguments = ArgOption.checkedNotNull)\n```\n\n## equals, hashCode, toString?\n[Derive4J philosophy is to be as safe and consistent as possible](https://github.com/derive4j/derive4j/issues/50). That is why Object.{equals, hashCode, toString} are not implemented by generated classes by default (they are best kept ignored as they break parametricity). Nonetheless, as a concession to legacy, it is possible to force Derive4J to implement them, by declaring them abstract. Eg by adding the following in your annotated class:\n```java\n  @Override\n  public abstract int hashCode();\n  @Override\n  public abstract boolean equals(Object obj);\n  @Override\n  public abstract String toString();\n```\nThe safer solution would be to never use those methods and use 'type classes' instead, eg. [Equal](https://github.com/functionaljava/functionaljava/blob/master/core/src/main/java/fj/Equal.java), [Hash](https://github.com/functionaljava/functionaljava/blob/master/core/src/main/java/fj/Hash.java) and [Show](https://github.com/functionaljava/functionaljava/blob/master/core/src/main/java/fj/Show.java).\nThe project [Derive4J for Functional Java](https://github.com/derive4j/derive4j-fj) aims to generate them automatically.\n\n## Pattern matching syntaxes\nNow let's say that you want a function that returns the body size of a ```Request```. Without Derive4J you would write something like:\n```java\n  static final Function\u003cRequest, Integer\u003e getBodySize = request -\u003e \n      request.match(new Cases\u003cInteger\u003e() {\n        public Integer GET(String path) {\n          return 0;\n        }\n        public Integer DELETE(String path) {\n          return 0;\n        }\n        public Integer PUT(String path, String body) {\n          return body.length();\n        }\n        public Integer POST(String path, String body) {\n          return body.length();\n        }\n      });\n```\nWith Derive4J you can do that a lot less verbosely, thanks to a generated fluent [structural pattern matching](http://www.deadcoderising.com/pattern-matching-syntax-comparison-in-scala-haskell-ml/) syntaxes! And it does exhaustivity check! (you must handle all cases). The above can be rewritten into:\n```java\nstatic final Function\u003cRequest, Integer\u003e getBodySize = Requests.cases()\n      .GET_(0) // shortcut for .Get(path -\u003e 0)\n      .DELETE_(0)\n      .PUT((path, body)  -\u003e body.length())\n      .POST((path, body) -\u003e body.length())\n```\nor even (because you don't care of GET and DELETE cases):\n```java\nstatic final Function\u003cRequest, Integer\u003e getBodySize = Requests.cases()\n      .PUT((path, body)  -\u003e body.length())\n      .POST((path, body) -\u003e body.length())\n      .otherwise_(0)\n```\nDerive4j also allows to match directly against a value:\n```java\nstatic int getBodyLength(Request request) {\n  return Requests.caseOf(request)\n      .PUT((path, body)  -\u003e body.length())\n      .POST((path, body) -\u003e body.length())\n      .otherwise_(0)\n}\n```\n\n## Accessors (getters)\nNow, pattern matching every time you want to inspect an instance of ```Request``` is a bit tedious. For this reason Derive4J generates 'getter' static methods for all fields. For the ```path``` and ```body``` fields, Derive4J will generate the following methods in the ```Requests``` class:\n```java\n  public static String getPath(Request request){\n    return Requests.cases()\n        .GET(path          -\u003e path)\n        .DELETE(path       -\u003e path)\n        .PUT((path, body)  -\u003e path)\n        .POST((path, body) -\u003e path)\n        .apply(request);\n  }\n  // return an Optional because the body is not present in the GET and DELETE cases:\n  static Optional\u003cString\u003e getBody(Request request){\n    return Requests.cases()\n        .PUT((path, body)  -\u003e body)\n        .POST((path, body) -\u003e body)\n        .otherwiseEmpty()\n        .apply(request);\n  }\n```\n(Actually the generated code is equivalent but more efficient)\n\nUsing the generated ```getBody``` methods, we can rewrite our ```getBodySize``` function into:\n```java\nstatic final Function\u003cRequest, Integer\u003e getBodySize = request -\u003e\n      Requests.getBody(request)\n              .map(String::length)\n              .orElse(0);\n```\n\n## Functional setters ('withers')\nThe most painful part of immutable data structures (like the one generated by Derive4J) is updating them. Scala case classes have ```copy``` methods for that. Derive4J generates similar modifier and setter methods in the ```Requests``` class:\n```java\n  public static Function\u003cRequest, Request\u003e setPath(String newPath){\n    return Requests.cases()\n            .GET(path          -\u003e Requests.GET(newPath))\n            .DELETE(path       -\u003e Requests.DELETE(newPath))\n            .PUT((path, body)  -\u003e Requests.PUT(newPath, body))\n            .POST((path, body) -\u003e Requests.POST(newPath, body)));\n  }\n  public static Function\u003cRequest, Request\u003e modPath(Function\u003cString, String\u003e pathMapper){\n    return Requests.cases()\n            .GET(path          -\u003e Requests.GET(pathMapper.apply(path)))\n            .DELETE(path       -\u003e Requests.DELETE(pathMapper.apply(path)))\n            .PUT((path, body)  -\u003e Requests.PUT(pathMapper.apply(path), body))\n            .POST((path, body) -\u003e Requests.POST(pathMapper.apply(path), body)));\n  }\n  public static Function\u003cRequest, Request\u003e setBody(String newBody){\n    return Requests.cases()\n            .GET(path          -\u003e Requests.GET(path))    // identity function for GET\n            .DELETE(path       -\u003e Requests.DELETE(path)) // and DELETE cases.\n            .PUT((path, body)  -\u003e Requests.PUT(path, newBody))\n            .POST((path, body) -\u003e Requests.POST(path, newBody)));\n  }\n  ...\n```\nBy returning a function, modifiers and setters allow for a lightweight syntax when [updating deeply nested immutable data structures](#updating-deeply-nested-immutable-data-structure).\n\n## First class laziness\nLanguages like Haskell provide laziness by default, which simplifies a lot of algorithms. In traditional Java you would have to declare a method argument as ```Supplier\u003cRequest\u003e``` (and do memoization) to emulate laziness. With Derive4J that is no more necessary as it generates a lazy constructor that gives you transparent lazy evaluation for all consumers of your data type:\n```java\n  // the requestExpression will be lazy-evaluated on the first call\n  // to the 'match' method of the returned Request instance:\n  public static Request lazy(Supplier\u003cRequest\u003e requestExpression) {\n    ...\n  }\n```\nHave a look at [List](https://github.com/derive4j/derive4j/blob/master/examples/src/main/java/org/derive4j/example/List.java) for how to implement a lazy cons list in Java using Derive4J (you may also want to see the associated [generated code](https://gist.github.com/jbgi/43c1bd0ab67e3f4b9634)). \n\n## Flavours\nIn the example above, we have used the default ```JDK``` flavour. Also available are ```FJ``` ([Functional Java](https://github.com/functionaljava/)),\n```Fugue``` ([Fugue](https://bitbucket.org/atlassian/fugue)),\n```Javaslang```/```Vavr``` ([Vavr](http://www.vavr.io/)),\n```HighJ``` ([HighJ](https://github.com/DanielGronau/highj)),\n```Guava``` and\n```Cyclops``` ([Cyclops-react](http://cyclops-react.io/)) flavours.\nWhen using those alternative flavours, Derive4J will use eg. the specific ```Option``` implementations from those projects instead of the jdk ```Optional``` class.\n\n## Optics (functional lenses)\nIf you are not familiar with optics, have a look at [Monocle](https://github.com/julien-truffaut/Monocle) (for Scala, but [Functional Java](https://github.com/functionaljava/functionaljava/) provides similar abstraction).\n\nUsing Derive4J generated code, defining optics is a breeze (you need to use the ```FJ``` flavour by specifying ```@Data(flavour = Flavour.FJ)```:\n```java\n  /**\n   * Lenses: optics focused on a field present for all data type constructors\n   * (getter cannot 'failed'):\n   */\n  public static final Lens\u003cRequest, String\u003e _path = lens(\n      Requests::getPath,\n      Requests::setPath);\n  /**\n   * Optional: optics focused on a field that may not be present for all constructors\n   * (getter return an 'Option'):\n   */\n  public static final Optional\u003cRequest, String\u003e _body = optional(\n      Requests::getBody,\n      Requests::setBody);\n  /**\n   * Prism: optics focused on a specific constructor:\n   */\n  public static final Prism\u003cRequest, String\u003e _GET = prism(\n      // Getter function\n      Requests.cases()\n          .GET(fj.data.Option::some)\n          .otherwise(Option::none),\n      // Reverse Get function (aka constructor)\n      Requests::GET);\n\n  // If there is more than one field, we use a tuple as the prism target:\n  public static final Prism\u003cRequest, P2\u003cString, String\u003e\u003e _POST = prism(\n      // Getter:\n      Requests.cases()\n          .POST((path, body) -\u003e p(path, body))\n          .otherwiseNone(),\n      // reverse get (construct a POST request given a P2\u003cString, String\u003e):\n      p2 -\u003e Requests.POST(p2._1(), p2._2()));\n}\n```\n# Smart constructors\nSometimes you want to validate the constructors parameters before returning an instance of a type. When using the `Smart` visibity (`@Data(@Derive(withVisibility = Visibility.Smart))`), Derive4J will not expose \"raw\" constructors and setter as public, but will use package private visibility for those methods instead (getters will still be public).\n\nThen you expose a public static factory method that will do the necessary validation of the arguments before returning an instance (typically wrapped in a `Option`/`Either`/`Validation`), and that public factory will be the only way to get an instance of that type.\n\nSee usage of this feature in [PersonName](https://github.com/derive4j/derive4j/blob/master/examples/src/main/java/org/derive4j/example/PersonName.java#L49).\n\n# Static methods export\n\nIt is generally considered good style to keep static methods and instance methods separated, especially because overloads could cause ambiguities on usage as method references.\n\nThe Java file generated by derive4j contains only static methods, so it makes sense to use this class as main entry point for the `static` part of the data type API.\n\nTo this end, Derive4J support re-exporting of your own manually-written static methods as part of the generated class API. It can do so in two ways (that can be combined):\n\n 1. by specifying that the main generated class must extends a given class eg. `MyStaticMethods.class`, thus exposing all its static methods through inheritance.\n 2. by annotating your package-private static methods with `@ExportAsPublic`: Derive4J will generate public forwarding methods in the generated class, and, as bonus, it will memoize the result of nullary methods.\n```java\n@Data(@Derive(extend = MyStaticMethods.class))\npublic abstract class List\u003cA\u003e {\n  // package-private static class with public static methods:\n  static abstract class MyStaticMethods {\n    public static \u003cA\u003e List\u003cA\u003e singleton(A a) {\n      return Lists.cons(a, Lists.nil())\n    }\n  }\n  // Or use the annotation, either in the above MyStaticMethods class\n  // or directly in the data type class:\n  @ExportAsPublic\n  static \u003cA\u003e List\u003cA\u003e singleton(A a) {\n    return Lists.cons(a, Lists.nil())\n  }\n}\n\npublic static void main(final String[] args) {\n  // enjoy single access points for all static methods:\n  List\u003cString\u003e a = Lists.singleton(\"a\");\n}\n```\n\nSee usage of this feature in [PersonName](https://github.com/derive4j/derive4j/blob/master/examples/src/main/java/org/derive4j/example/PersonName.java#L49).\n\n# Updating deeply nested immutable data structure\nLet's say you want to model a CRM. Each client is a ```Person``` who can be contacted by email, by telephone or by postal mail. With Derive4J you could write the following:\n```java\nimport org.derive4j.*;\nimport java.util.function.BiFunction;\n\n@Data\npublic abstract class Address {\n  public abstract \u003cR\u003e R match(@FieldNames({\"number\", \"street\"}) \n  \t\t\t      BiFunction\u003cInteger, String, R\u003e Address);\n}\n```\n```java\nimport org.derive4j.Data;\n\n@Data\npublic abstract class Contact {\n    interface Cases\u003cR\u003e {\n      R byEmail(String email);\n      R byPhone(String phoneNumber);\n      R byMail(Address postalAddress);\n    }\n    public abstract \u003cR\u003e R match(Cases\u003cR\u003e cases);\n}\n```\n```java\nimport org.derive4j.*;\nimport java.util.function.BiFunction;\n\n@Data\npublic abstract class Person {\n  public abstract \u003cR\u003e R match(@FieldNames({\"name\", \"contact\"})\n                              BiFunction\u003cString, Contact, R\u003e Person);\n}\n```\nBut now we have a problem: All the clients have been imported from a legacy database with an off-by-one error for the street number! We must create a function that increments each ```Person```'s street number (if it exists) by one. And we have to do this without modifying the original data structure (because it is immutable).\nWith Derive4J, writing such a function is trivial:\n```java\nimport java.util.Optional;\nimport java.util.function.Function;\n\nimport static org.derive4j.example.Addresss.Address;\nimport static org.derive4j.example.Addresss.getNumber;\nimport static org.derive4j.example.Addresss.modNumber;\nimport static org.derive4j.example.Contacts.getPostalAddress;\nimport static org.derive4j.example.Contacts.modPostalAddress;\nimport static org.derive4j.example.Persons.Person;\nimport static org.derive4j.example.Persons.getContact;\nimport static org.derive4j.example.Persons.modContact;\n\n  public static void main(String[] args) {\n\n    Person joe = Person(\"Joe\", Contacts.byMail(Address(10, \"Main St\")));\n\n    Function\u003cPerson, Person\u003e incrementStreetNumber = modContact(\n    \t\t\t\t\t\t       modPostalAddress(\n    \t\t\t\t\t\t         modNumber(number -\u003e number + 1)));\n    \n    // correctedJoe is a copy of joe with the street number incremented:\n    Person correctedJoe = incrementStreetNumber.apply(joe);\n\n    Optional\u003cInteger\u003e newStreetNumber = getPostalAddress(getContact(correctedJoe))\n        .map(postalAddress -\u003e getNumber(postalAddress));\n\n    System.out.println(newStreetNumber); // print \"Optional[11]\" !!\n  }\n```\n\n\n# Popular use-case: domain specific languages\nAlgebraic data types are particulary well fitted for creating DSLs. A calculator for arithmetic expressions could be built like this:\n```java\nimport java.util.function.Function;\nimport org.derive4j.Data;\nimport static org.derive4j.example.Expressions.*;\n\n@Data\npublic abstract class Expression {\n\n\tinterface Cases\u003cR\u003e {\n\t\tR Const(Integer value);\n\t\tR Add(Expression left, Expression right);\n\t\tR Mult(Expression left, Expression right);\n\t\tR Neg(Expression expr);\n\t}\n\t\n\tpublic abstract \u003cR\u003e R match(Cases\u003cR\u003e cases);\n\n\tprivate static Function\u003cExpression, Integer\u003e eval = Expressions\n\t\t.cases()\n\t\t\t.Const(value        -\u003e value)\n\t\t\t.Add((left, right)  -\u003e eval(left) + eval(right))\n\t\t\t.Mult((left, right) -\u003e eval(left) * eval(right))\n\t\t\t.Neg(expr           -\u003e -eval(expr));\n\n\tpublic static Integer eval(Expression expression) {\n\t\treturn eval.apply(expression);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tExpression expr = Add(Const(1), Mult(Const(2), Mult(Const(3), Const(3))));\n\t\tSystem.out.println(eval(expr)); // (1+(2*(3*3))) = 19\n\t}\n}\n```\n# Catamorphisms\nare generated for recursively defined datatypes. So that you can rewrite the above ```eval``` method into:\n```java\n\tpublic static Integer eval(Expression expression) {\n\t\tExpressions\n\t\t     .cata(\n\t\t        value -\u003e value,\n\t\t        (left, right) -\u003e left + right,\n\t\t        (left, right) -\u003e left * right,\n\t\t        expr -\u003e -expr,\n\t\t        Supplier::get\n\t\t     )\n\t\t     .apply(expression)\n\t}\n```\nThe last parameter (`Supplier::get` above) specify how recursive calls are suspended.\nUsing `Supplier::get` means that the computation is not suspended: for deep structures it may blow the stack!\n\nTo be safe, use the `lazy`, (or `delay` or `suspend` or `defer`...) constructor of your result type, such as the lazy constructor generated by Derive4J.\n\nIf no such constructor is available then your safe option is to use a `Trampoline`, such as the one provided by FunctionalJava:\n```java\npublic static Integer stackSafeEval(Expression expression) {\n    Expressions.cata(\n        value -\u003e Trampoline.pure(value),\n        (left, right) -\u003e left.zipWith(right, (l, r) -\u003e l + r),\n        (left, right) -\u003e left.zipWith(right, (l, r) -\u003e l * r),\n        expr -\u003e expr.map(i -\u003e -i),\n        Trampoline::suspend\n    ).f(expression).run();\n}\n ```\n\n# Extensible algebraic data types\n\nAlgebraic data types defined as fix-point (aka initial algebra) of an object algebras can enjoy [their extensibility properties](https://www.cs.utexas.edu/~wcook/Drafts/2012/ecoop2012.pdf).\n\n## When the data type is not inductive the extensibility property comes directly from covariance\n\nEg. an event type for an inventory service:\n```java\n  @Data\n  interface EventV1 {\n\n    interface Cases\u003cR\u003e {\n      R newItem(Long ref, String itemName);\n      R itemRemoved(Long ref);\n    }\n\n    \u003cR\u003e R match(Cases\u003cR\u003e cases);\n  }\n```\n\nThen comes a new version of the service, with enriched events and new cases.\nIf the visitor for the new event type extend the old visitor interface then old events can be easily converted to new events, without change to the old classes:\n\n```java\n  @Data\n  interface EventV2 {\n\n    interface Cases\u003cR\u003e extends EventV1.Cases\u003cR\u003e { // extends V1 with:\n\n      // new `initialStock` field in `newItem` event:\n      R newItem(Long ref, String itemName, int initialStock);\n      // default to 0 for old events:\n      @Override\n      default R newItem(Long ref, String itemName) {\n        return newItem(ref, itemName, 0);\n      }\n      // new event:\n      R itemRenamed(Long ref, String newName);\n    }\n\n    \u003cR\u003e R match(Cases\u003cR\u003e cases);\n\n    static EventV2 fromV1(EventV1 v1Event) {\n      // Events are (polymorphic) functions!\n      // And functions are contra-variant in type argument,\n      // thus we can use method reference to convert from V1 to V2:\n      return v1Event::match;\n    }\n  }\n```\n\n\n## Extensible inductive data types via hylomorphisms\n\nAka solving the expression problem via object-algebras used as visitor.\nFor this, we need to slightly change the visitor of the above `Expression` so that a type variable (`E`) is used instead of the self-reference:\n\n```java\n@Data\ninterface Exp {\n\n  interface ExpAlg\u003cE, R\u003e {\n    R Lit(int lit);\n    R Add(E e1, E e2);\n  }\n\n  \u003cR\u003e R accept(ExpAlg\u003cExp, R\u003e alg);\n}\n```\nWhen data types are defined is such a way (as a fix-point of the algebra), Derive4J generate (by default) an instance of the visitor/algebra that can serve as factory (aka. anamorphism).\nUsing this factory as an argument to compatible catamorphism (thus creating a hylomorphism) we obtain a conversion function from one ADT to another.\n\nEg. we can create a new data type that add a multiplication case to the above data type, and still be able to maximally reuse the existing code without modification:\n\n```java\n@Data\ninterface ExpMul {\n\n  interface ExpMulAlg\u003cE, R\u003e extends Exp.ExpAlg\u003cE, R\u003e {\n    R Mul(E e1, E e2);\n  }\n\n  \u003cR\u003e R accept(ExpMulAlg\u003cExpMul, R\u003e alg);\n\n  static Function\u003cExp, ExpMul\u003e fromExp() {\n    ExpMulAlg\u003cExpMul, ExpMul\u003e factory = ExpMuls.factory();\n    return Exps.cata(factory, ExpMuls::lazy);\n  }\n}\n```\n\nTo ensure smooth extensibility across compilation unit (or even during incremental compilation), it is best to **use the `-parameters` option of javac**.\n\n# But what exactly is generated?\nThis is a very legitimate question. Here is the [```ExpMuls.java```](https://gist.github.com/jbgi/31b891f00566feb301f8100762ee8511#file-expmuls-java) file that is generated for the above ```@Data ExpMul``` type.\n\n# Parametric polymorphism\n... works as expected. For example, you can write the following:\n```java\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport org.derive4j.Data;\n\n@Data\npublic abstract class Option\u003cA\u003e {\n\n    public abstract \u003cR\u003e R cata(Supplier\u003cR\u003e none, Function\u003cA, R\u003e some);\n\n    public final \u003cB\u003e Option\u003cB\u003e map(final Function\u003cA, B\u003e mapper) {\n        return Options.modSome(mapper).apply(this);\n    }\n}\n```\nThe generated modifier method ```modSome``` allows polymorphic update and is incidentaly the functor for our ```Option```!\n\n# Generalized Algebraic Data Types\n\nGADTs are also supported out of the box by Derive4J (within the limitations of the Java type system). Here is how you can translate the example from [Fun with phantom types](http://www.cs.ox.ac.uk/ralf.hinze/publications/With.pdf):\n```java\nimport org.derive4j.hkt.TypeEq;\n\n@Data\npublic abstract class Term\u003cT\u003e {\n  interface Cases\u003cA, R\u003e {\n    R Zero(TypeEq\u003cInteger, A\u003e id);\n    R Succ(Term\u003cInteger\u003e pred, TypeEq\u003cInteger, A\u003e id);\n    R Pred(Term\u003cInteger\u003e succ, TypeEq\u003cInteger, A\u003e id);\n    R IsZero(Term\u003cInteger\u003e a, TypeEq\u003cBoolean, A\u003e id);\n    R If(Term\u003cBoolean\u003e cond, Term\u003cA\u003e then, Term\u003cA\u003e otherwise);\n  }\n\n  public abstract \u003cX\u003e X match(Cases\u003cT, X\u003e cases);\n\n  public static \u003cT\u003e T eval(final Term\u003cT\u003e term) {\n\n    return Terms.caseOf(term).\n        Zero(id -\u003e id.coerce(0)).\n        Succ((t, id) -\u003e id.coerce(eval(t) + 1)).\n        Pred((t, id) -\u003e id.coerce(eval(t) - 1)).\n        IsZero((t, id) -\u003e id.coerce(eval(t) == 0)).\n        If((cond, then, otherwise) -\u003e eval(cond)\n            ? eval(then)\n            : eval(otherwise));\n  }\n\n  public static void main(final String[] args) {\n\n    Term\u003cInteger\u003e one = Succ(Zero());\n    out.println(eval(one)); // \"1\"\n    out.println(eval(IsZero(one))); // \"false\"\n    // IsZero(IsZero(one)); // does not compile:\n    // \"The method IsZero(Term\u003cInteger\u003e) in the type Term\u003cT\u003e is not\n    // applicable for the arguments (Term\u003cBoolean\u003e)\"\n    out.println(eval(If(IsZero(one), Zero(), one))); // \"1\"\n    Term\u003cBoolean\u003e True = IsZero(Zero());\n    Term\u003cBoolean\u003e False = IsZero(one);\n    out.println(eval(If(True, True, False))); // \"true\"\n    // out.println(prettyPrint(If(True, True, False), 0)); // \"if IsZero(0)\n    //  then IsZero(0)\n    //  else IsZero(Succ(0))\"\n  }\n}\n\n```\nFor GADT you will need to add a dependency on [derive4j/hkt](https://github.com/derive4j/hkt) which provides `TypeEq\u003cA, B\u003e`: a witness of the equality of two types, `A` and `B`.\n\n# DRY annotation configuration\nBy default the `@Data` annotation triggers the generation of [everything which is available](/annotation/src/main/java/org/derive4j/Make.java#L22), in a file whose name is the English plural of the annotated class. But you may want to restrict the scope of what is generated, or change the name of the file, and you usually want all you ADTs to use the same flavour. You may even dislike the name of the annotation because it clashes with another framework...\n\nFor example, let's say that you want to always use the `FJ` flavour (FunctionalJava), make the generated code package private in a class suffixed by `Impl` and only generate the pattern matching syntax and the constructors. Then all you have to do is to create the following annotation:\n```java\n@Data(flavour = Flavour.FJ, value = @Derive(\n    inClass = \"{ClassName}Impl\",\n    withVisibility = Visibility.Package,\n    make = { Make.constructors, Make.caseOfMatching }\n))\npublic @interface myADT {}\n```\nAnd you annotate your classes with `@myADT` instead of `@Data`, saving on that configuration every time.\n\nBut now for some of your ADTs you may want to also generate getters and functional setters. In order to not lose the benefits of your `@myADT`, derive4j allows you to do this:\n```java\n@myADT\n@Derive(make = { Make.getters, Make.modifiers }) // add-up to the @myADT configuration\npublic abstract class Adt {...}\n\n```\n\n# Use it in your project\nDerive4J should be declared as a compile-time only dependency (not needed at runtime). So while derive4j is (L)GPL-licensed, the generated code is not linked to derive4j, and thus __derive4j can be used in any project (proprietary or not)__.\n## Maven:\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.derive4j\u003c/groupId\u003e\n  \u003cartifactId\u003ederive4j\u003c/artifactId\u003e\n  \u003cversion\u003e1.1.1\u003c/version\u003e\n  \u003coptional\u003etrue\u003c/optional\u003e\n\u003c/dependency\u003e\n```\n[search.maven]: http://search.maven.org/#search|ga|1|org.derive4j.derive4j\n\n## Gradle\n```\ncompile(group: 'org.derive4j', name: 'derive4j', version: '1.1.1', ext: 'jar')\n```\nor better using the [gradle-apt-plugin](https://github.com/tbroyer/gradle-apt-plugin):\n```\ncompileOnly \"org.derive4j:derive4j-annotation:1.1.1\"\napt \"org.derive4j:derive4j:1.1.1\"\n```\n## Contributing\n\nBug reports and feature requests are welcome, as well as contributions to improve documentation.\n\nRight now the codebase is not ready for external contribution (many blocks of code are more complicated than they should be). So you might be better off waiting for the resolution of [#2](https://github.com/derive4j/derive4j/issues/2) before trying to dig into the codebase.\n\n## Contact\njb@giraudeau.info, [@jb9i](https://twitter.com/jb9i) or use the project GitHub issues.\n\n## Further reading\n\n- [Encoding FP in Java](https://gracious-hypatia-aac58b.netlify.com/) (and links)\n- http://eng.wealthfront.com/2015/02/pattern-matching-in-java-with-visitor.html\n- https://en.wikipedia.org/wiki/Algebraic_data_type\n- https://en.wikipedia.org/wiki/Tagged_union\n- http://blog.higher-order.com/blog/2009/08/21/structural-pattern-matching-in-java/\n- http://tomasp.net/blog/types-and-math.aspx/\n- http://fsharpforfunandprofit.com/posts/type-size-and-design/\n- https://codewords.recurse.com/issues/three/algebra-and-calculus-of-algebraic-data-types\n- http://chris-taylor.github.io/blog/2013/02/10/the-algebra-of-algebraic-data-types/\n\n## Thanks\n\nThis project has a special dedication to Tony Morris' blog post [Debut with a catamorphism](http://blog.tmorris.net/posts/debut-with-a-catamorphism/index.html).\nI'm also very thankful to [@sviperll](https://github.com/sviperll) and his [adt4j](https://github.com/sviperll/adt4j/) project which was the initial inspiration for Derive4J.\n","funding_links":[],"categories":["Projects","项目","Java","I. Development","Metaprogramming","Functional Programming","Functional libraries","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":["Functional Programming","函数式编程","6. Useful libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderive4j%2Fderive4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fderive4j%2Fderive4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderive4j%2Fderive4j/lists"}