Skip to content

Instantly share code, notes, and snippets.

@jbgi
Last active May 7, 2017 21:40
Show Gist options
  • Save jbgi/09e0ac4ff49868cae938afbbd59bea58 to your computer and use it in GitHub Desktop.
Save jbgi/09e0ac4ff49868cae938afbbd59bea58 to your computer and use it in GitHub Desktop.

Revisions

  1. jbgi revised this gist May 7, 2017. 2 changed files with 78 additions and 0 deletions.
    22 changes: 22 additions & 0 deletions Either.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    import fj.Equal;
    import fj.Hash;
    import fj.Ord;
    import fj.Show;
    import java.util.function.Function;
    import org.derive4j.Data;
    import org.derive4j.Derive;
    import org.derive4j.Instances;

    @Data(@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(Function<A, X> left, Function<B, X> right);

    }
    56 changes: 56 additions & 0 deletions Eithers.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,56 @@
    // Generated from above
    public final class Eithers {
    //...

    // Gnenerated from above (not very optimized yet):

    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)
    ));
    }
    }
  2. jbgi renamed this gist May 7, 2017. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. jbgi created this gist May 7, 2017.
    182 changes: 182 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,182 @@
    /*
    * Copyright (c) 2017, Jean-Baptiste Giraudeau <[email protected]>
    *
    * This file is part of "Derive4J - FunctionalJava derivators".
    *
    * "Derive4J - FunctionalJava derivators" is free software: you can redistribute it
    * and/or modify it under the terms of the GNU General Public License
    * as published by the Free Software Foundation, either version 3 of the License,
    * or (at your option) any later version.
    *
    * "Derive4J - FunctionalJava derivators" is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License
    * along with "Derive4J - FunctionalJava derivators". If not, see <http://www.gnu.org/licenses/>.
    */
    package org.derive4j.fj;

    import com.google.auto.service.AutoService;
    import com.squareup.javapoet.ClassName;
    import com.squareup.javapoet.CodeBlock;
    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    import org.derive4j.processor.api.DerivatorFactory;
    import org.derive4j.processor.api.DerivatorSelection;
    import org.derive4j.processor.api.DeriveUtils;

    import static java.util.Arrays.asList;
    import static java.util.Collections.emptyList;
    import static org.derive4j.processor.api.DerivatorSelections.selection;

    @AutoService(DerivatorFactory.class)
    public final class FunctionalJavaTypeClassesDerivations implements DerivatorFactory {

    private static final List<Integer> PRIMES = asList(23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
    107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239,
    241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389,
    397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557,
    563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709,
    719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881,
    883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997);

    @Override
    public List<DerivatorSelection> derivators(DeriveUtils deriveUtils) {

    final ClassName showClass = ClassName.get("fj", "Show");
    final ClassName hashClass = ClassName.get("fj", "Hash");
    final ClassName equalClass = ClassName.get("fj", "Equal");
    final ClassName ordClass = ClassName.get("fj", "Ord");
    final ClassName ordering = ClassName.get("fj", "Ordering");
    final ClassName streamClass = ClassName.get("fj.data", "Stream");

    return asList(

    selection(showClass, adt -> deriveUtils.generateInstance(adt, showClass, emptyList(), instanceUtils ->

    instanceUtils.generateInstanceFactory(CodeBlock.builder()
    .add("$1T.show($2L -> $2L.", showClass, instanceUtils.adtVariableName())
    .add(instanceUtils.matchImpl(constructor -> deriveUtils.lambdaImpl(constructor, CodeBlock.builder()
    .add("$T.fromString($S).append(() -> ", streamClass, constructor.name() + "(")
    .add(constructor.arguments()
    .stream()
    .map(da -> instanceUtils.instanceFor(da).toBuilder().add(".show($L)", da.fieldName()).build())
    .reduce((cb1, cb2) -> cb1.toBuilder()
    .add(".append($T.fromString($S)).append(() -> ", streamClass, ", ")
    .add(cb2)
    .add(")")
    .build())
    .orElse(CodeBlock.of("$T.nil()", streamClass)))
    .add(").append($T.fromString($S))", streamClass, ")")
    .build())))
    .add(")")
    .build())

    )),

    selection(hashClass, adt -> deriveUtils.generateInstance(adt, hashClass, emptyList(), instanceUtils ->

    instanceUtils.generateInstanceFactory(CodeBlock.builder()
    .add("$1T.hash($2L -> $2L.", hashClass, instanceUtils.adtVariableName())
    .add(instanceUtils.matchImpl(constructor -> {
    int nbConstructors = adt.dataConstruction().constructors().size();
    int constructorIndex = IntStream.range(0, nbConstructors)
    .filter(i -> adt.dataConstruction().constructors().get(i).name().equals(constructor.name()))
    .findFirst()
    .getAsInt();

    return deriveUtils.lambdaImpl(constructor, CodeBlock.builder()
    .add("$L", IntStream.range(0, constructor.arguments().size() - 1)
    .mapToObj(__ -> "(")
    .collect(Collectors.joining()))
    .add(PRIMES.get(constructorIndex).toString())
    .add(constructor.arguments()
    .stream()
    .map(da -> CodeBlock.builder()
    .add(" + ")
    .add(instanceUtils.instanceFor(da))
    .add(".hash($L)", da.fieldName())
    .build())
    .reduce((cb1, cb2) -> cb1.toBuilder().add(") * " + PRIMES.get(constructorIndex)).add(cb2).build())
    .orElse(CodeBlock.of("")))
    .build());
    }))
    .add(")")
    .build())

    )),

    selection(equalClass, adt -> deriveUtils.generateInstance(adt, equalClass, emptyList(), instanceUtils ->

    instanceUtils.generateInstanceFactory(CodeBlock.builder()
    .add("$1T.equalDef($2L -> $2L.", equalClass, instanceUtils.adtVariableName() + 1)
    .add(instanceUtils.matchImpl(constructor -> {

    String adt2 = instanceUtils.adtVariableName() + 2;

    return deriveUtils.lambdaImpl(constructor, "1", CodeBlock.builder()
    .add("$1L -> $1L.", adt2)
    .add(instanceUtils.matchImpl(constructor2 -> deriveUtils.lambdaImpl(constructor2, "2",
    constructor.name().equals(constructor2.name())
    ? constructor.arguments()
    .stream()
    .map(da -> CodeBlock.builder()
    .add(instanceUtils.instanceFor(da))
    .add(".eq($L, $L)", da.fieldName() + "1", da.fieldName() + "2")
    .build())
    .reduce((cb1, cb2) -> cb1.toBuilder().add(" && ").add(cb2).build())
    .orElse(CodeBlock.of("true"))
    : CodeBlock.of("false"))))
    .build());
    }))
    .add(")")
    .build())

    )),

    selection(ordClass, adt -> deriveUtils.generateInstance(adt, ordClass, emptyList(), instanceUtils ->

    instanceUtils.generateInstanceFactory(CodeBlock.builder()
    .add("$1T.ordDef($2L -> $2L.", ordClass, instanceUtils.adtVariableName() + 1)
    .add(instanceUtils.matchImpl(constructor -> {

    String adt2 = instanceUtils.adtVariableName() + 2;

    return deriveUtils.lambdaImpl(constructor, "1", CodeBlock.builder()
    .add("$1L -> $1L.", adt2)
    .add(instanceUtils.matchImpl(constructor2 -> deriveUtils.lambdaImpl(constructor2, "2",
    constructor.name().equals(constructor2.name())
    ? CodeBlock.builder()
    .add("{\n")
    .indent()
    .addStatement("$1T o = $1T.EQ", ordering)
    .add(constructor.arguments()
    .stream()
    .map(da -> CodeBlock.builder()
    .add("o = ")
    .add(instanceUtils.instanceFor(da))
    .add(".compare($L, $L);\n", da.fieldName() + "1", da.fieldName() + "2")
    .addStatement("if (o != $T.EQ) return o", ordering)
    .build())
    .reduce((cb1, cb2) -> cb1.toBuilder().add(cb2).build())
    .orElse(CodeBlock.of("")))
    .addStatement("return o")
    .unindent()
    .add("}")
    .build()
    : CodeBlock.of("$T.$L", ordering, constructor.index() < constructor2.index()
    ? "LT"
    : "GT"))))
    .build());
    }))
    .add(")")
    .build())

    ))

    );

    }