All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jnape.palatable.lambda.adt.hlist.HList Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
package com.jnape.palatable.lambda.adt.hlist;

import java.util.Objects;

/**
 * An immutable heterogeneous list supporting arbitrary depth type-safety via a linearly recursive type signature. Note
 * that due to its rapidly expanding type signature, specializations exist up to certain depths to minimize typing
 * overhead.
 *
 * @param  The head element type
 * @param  The encoded recursive tail HList type
 * @see SingletonHList
 * @see Tuple2
 * @see Tuple3
 * @see Tuple4
 * @see Tuple5
 */
public abstract class HList> {

    private HList() {
    }

    /**
     * Cons an element onto the front of this HList.
     *
     * @param newHead   the new head element
     * @param  the new head type
     * @return the updated HList
     */
    public abstract  HCons> cons(NewHead newHead);

    @Override
    public final String toString() {
        StringBuilder body = new StringBuilder("HList{");

        HList next = this;
        while (next != HNil.INSTANCE) {
            HCons hCons = (HCons) next;
            body.append(" ").append(hCons.head).append(" ");
            next = hCons.tail;
            if (next != HNil.INSTANCE)
                body.append("::");
        }

        return body.append("}").toString();
    }

    /**
     * Static factory method for creating empty HLists.
     *
     * @return an empty HList
     */
    public static HNil nil() {
        return HNil.INSTANCE;
    }

    /**
     * Static factory method for creating an HList from the given head and tail.
     *
     * @param head   the head element
     * @param tail   the tail HList
     * @param  the head type
     * @param  the tail type
     * @return the newly created HList
     */
    public static > HCons cons(Head head, Tail tail) {
        return new HCons<>(head, tail);
    }

    /**
     * Static factory method for creating a singleton HList.
     *
     * @param head   the head element
     * @param  the head element type
     * @return the singleton HList
     */
    public static  SingletonHList singletonHList(Head head) {
        return new SingletonHList<>(head);
    }

    /**
     * Static factory method for creating a 2-element HList.
     *
     * @param _1   the head element
     * @param _2   the second element
     * @param <_1> the head element type
     * @param <_2> the second element type
     * @return the 2-element HList
     * @see Tuple2
     */
    @SuppressWarnings("JavaDoc")
    public static <_1, _2> Tuple2<_1, _2> tuple(_1 _1, _2 _2) {
        return singletonHList(_2).cons(_1);
    }

    /**
     * Static factory method for creating a 3-element HList.
     *
     * @param _1   the head element
     * @param _2   the second element
     * @param _3   the third element
     * @param <_1> the head element type
     * @param <_2> the second element type
     * @param <_3> the third element type
     * @return the 3-element HList
     * @see Tuple3
     */
    @SuppressWarnings("JavaDoc")
    public static <_1, _2, _3> Tuple3<_1, _2, _3> tuple(_1 _1, _2 _2, _3 _3) {
        return tuple(_2, _3).cons(_1);
    }

    /**
     * Static factory method for creating a 4-element HList.
     *
     * @param _1   the head element
     * @param _2   the second element
     * @param _3   the third element
     * @param _4   the fourth element
     * @param <_1> the head element type
     * @param <_2> the second element type
     * @param <_3> the third element type
     * @param <_4> the fourth element type
     * @return the 4-element HList
     * @see Tuple4
     */
    @SuppressWarnings("JavaDoc")
    public static <_1, _2, _3, _4> Tuple4<_1, _2, _3, _4> tuple(_1 _1, _2 _2, _3 _3, _4 _4) {
        return tuple(_2, _3, _4).cons(_1);
    }

    /**
     * Static factory method for creating a 5-element HList.
     *
     * @param _1   the head element
     * @param _2   the second element
     * @param _3   the third element
     * @param _4   the fourth element
     * @param _5   the fifth element
     * @param <_1> the head element type
     * @param <_2> the second element type
     * @param <_3> the third element type
     * @param <_4> the fourth element type
     * @param <_5> the fifth element type
     * @return the 5-element HList
     * @see Tuple5
     */
    @SuppressWarnings("JavaDoc")
    public static <_1, _2, _3, _4, _5> Tuple5<_1, _2, _3, _4, _5> tuple(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5) {
        return tuple(_2, _3, _4, _5).cons(_1);
    }

    /**
     * The consing of a head element to a tail HList.
     *
     * @param  the head element type
     * @param  the HList tail type
     */
    public static class HCons> extends HList {
        private final Head head;
        private final Tail tail;

        HCons(Head head, Tail tail) {
            this.head = head;
            this.tail = tail;
        }

        /**
         * The head element of the HList.
         *
         * @return the head element
         */
        public Head head() {
            return head;
        }

        /**
         * The remaining tail of the HList; returns an HNil if this is the last element.
         *
         * @return the tail
         */
        public Tail tail() {
            return tail;
        }

        @Override
        public  HCons> cons(NewHead newHead) {
            return new HCons<>(newHead, this);
        }

        @Override
        public final boolean equals(Object other) {
            if (other instanceof HCons) {
                HCons that = (HCons) other;
                return this.head.equals(that.head)
                        && this.tail.equals(that.tail);
            }
            return false;
        }

        @Override
        public final int hashCode() {
            return 31 * Objects.hashCode(head) + tail.hashCode();
        }
    }

    /**
     * The empty HList.
     */
    public static final class HNil extends HList {
        private static final HNil INSTANCE = new HNil();

        private HNil() {
        }

        @Override
        public  SingletonHList cons(Head head) {
            return new SingletonHList<>(head);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy