Giter VIP home page Giter VIP logo

derive4j-fj's Introduction

FunctionalJava on Derive4J steroids!

This Derive4J extension permits automatic derivation of FunctionalJava instances for the following type classes:

(generation of optics is planned).

So, now, no excuse to write unsafe code that breaks parametricity! ;)

"Implicit" resolution of instances

The implementation of a type class instance may often depends on the instances of the data type fields. Derive4J will try its best to resolve those dependencies for you, following rules similar to scala implicit resolution. In some cases, Derive4J can fail to find a valid instance for a field, for one of the following two reasons:

  • because it does not exist (in the expected classes, ie. its an "orphan instance")
  • or because the instance for that field is not yet generated AND the field type is parametrized.

In both cases you will have to provide a static field or method (in the class of the ADT under derivation) that returns the missing type class instance. The implementation can simply be a forward to a generated instance (for the second case).

Example Usage:

import fj.*;
import org.derive4j.*;

@Data(flavour = Flavour.FJ)
@Derive(@Instances({ Show.class, Hash.class, Equal.class, Ord.class}))
public abstract class Either<A, B> {

  /**
   * The catamorphism for either. Folds over this either breaking into left or right.
   *
   * @param left The function to call if this is left.
   * @param right The function to call if this is right.
   * @return The reduced value.
   */
  public abstract <X> X either(F<A, X> left, F<B, X> right);


  // In case you need to interact with unsafe code that
  // expects hashCode/equal/toString to be implemented:

  @Deprecated
  @Override
  public final boolean equals(Object obj) {
    return Equal.equals0(Either.class, this, obj,
        Eithers.eitherEqual(Equal.anyEqual(), Equal.anyEqual()));
  }

  @Deprecated
  @Override
  public final int hashCode() {
    return Eithers.<A, B>eitherHash(Hash.anyHash(), Hash.anyHash()).hash(this);
  }

  @Deprecated
  @Override
  public final String toString() {
    return Eithers.<A, B>eitherShow(Show.anyShow(), Show.anyShow()).showS(this);
  }
}

Derive4J, through this extension will then derive the following code in the generated Eithers.java file:

  
  public static <A, B> Show<Either<A, B>> eitherShow(Show<A> aShow, Show<B> bShow) {
    return Show.show(either -> either.either(
      (left) -> Stream.fromString("left(").append(() -> aShow.show(left)).append(Stream.fromString(")")),
      (right) -> Stream.fromString("right(").append(() -> bShow.show(right)).append(Stream.fromString(")"))
    ));
  }

  public static <A, B> Ord<Either<A, B>> eitherOrd(Ord<A> aOrd, Ord<B> bOrd) {
    return Ord.ordDef(either1 -> either1.either(
      (left1) -> either2 -> either2.either(
        (left2) -> {
          Ordering o = Ordering.EQ;
          o = aOrd.compare(left1, left2);
          if (o != Ordering.EQ) return o;
          return o;
        },
        (right2) -> Ordering.LT
      ),
      (right1) -> either2 -> either2.either(
        (left2) -> Ordering.GT,
        (right2) -> {
          Ordering o = Ordering.EQ;
          o = bOrd.compare(right1, right2);
          if (o != Ordering.EQ) return o;
          return o;
        }
      )
    ));
  }

  public static <A, B> Equal<Either<A, B>> eitherEqual(Equal<A> aEqual, Equal<B> bEqual) {
    return Equal.equalDef(either1 -> either1.either(
      (left1) -> either2 -> either2.either(
        (left2) -> aEqual.eq(left1, left2),
        (right2) -> false
      ),
      (right1) -> either2 -> either2.either(
        (left2) -> false,
        (right2) -> bEqual.eq(right1, right2)
      )
    ));
  }

  public static <A, B> Hash<Either<A, B>> eitherHash(Hash<A> aHash, Hash<B> bHash) {
    return Hash.hash(either -> either.either(
      (left) -> 23 + aHash.hash(left),
      (right) -> 29 + bHash.hash(right)
    ));
}

Use it in your project

Derive4J-FJ is a "plugin" of Derive4J and should be declared (as well) as a apt/compile-time only dependency (not needed at runtime). So while derive4j and derive4j-fj are (L)GPL-licensed, the generated code is not linked to derive4j, and thus derive4j can be used in any project (proprietary or not). Also you will need jdk8 version of FunctionalJava artifacts (4.7+).

Maven:

<dependency>
    <groupId>org.functionaljava</groupId>
    <artifactId>functionaljava_1.8</artifactId>
    <version>4.7</version>
</dependency>
<dependency>
  <groupId>org.derive4j</groupId>
  <artifactId>derive4j-fj</artifactId>
  <version>0.2</version>
  <optional>true</optional>
</dependency>
<dependency>
  <groupId>org.derive4j</groupId>
  <artifactId>derive4j</artifactId>
  <version>0.12.4</version>
  <optional>true</optional>
</dependency>

Gradle

compile "org.functionaljava:functionaljava_1.8:4.7"
compile(group: 'org.derive4j', name: 'derive4j', version: '0.12.4', ext: 'jar')
compile(group: 'org.derive4j', name: 'derive4j-fj', version: '0.2', ext: 'jar')

or better using the gradle-apt-plugin:

compile "org.functionaljava:functionaljava_1.8:4.7"
compileOnly "org.derive4j:derive4j-annotation:0.12.4"
apt "org.derive4j:derive4j:0.12.4"
apt "org.derive4j:derive4j-fj:0.2"

Contributing

Bug reports, feature requests and pull requests are welcome, as well as contributions to improve documentation.

Contact

[email protected], @jb9i or use the project GitHub issues.

derive4j-fj's People

Contributors

jbgi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

derive4j-fj's Issues

Duplicated identifiers in generated code

Given

public abstract class Property<T> implements __<Property.µ, T> {
    public enum µ {}
    Property() {}

    interface Cases<T, R> {
        R Simple(Class<T> ownerClass
            , String name
            , Value value
            , List<Param> params);

        R Multi(Class<T> ownerClass
            , String name
            , List<Value> values
            , List<Param> params);
    }
    public abstract <R> R match(Cases<T, R> cases);
}

we obtain

public static <T> Ord<Property<T>> propertyOrd() {
    Ord<Property<T>> _propertyOrd = propertyOrd;
    if (_propertyOrd == null) {
      Ord<List<Property.Param>> listOrd = Ord.listOrd(_PropParam.paramOrd());
      Ord<List<Property.Value>> listOrd = Ord.listOrd(_PropVal.valueOrd());
      propertyOrd = _propertyOrd = Ord.ordDef(property1 -> property1.match(cases(
...

which doesn't compile (duplicate identifier listOrd)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.