The selector pattern

Samuel Dennis Borlongan srborlongan at gmail.com
Tue Jan 28 07:26:06 PST 2014


Tried to create an implementation (renamed Cell because Picolisp calls it
Cell) off the top of my head:

@FunctionalInterface
public interface FunctionalField<FIELD extends Enum<?>> {
  public Object untypedField(FIELD field);

  @SuppressWarnings("unchecked")
  public default <VALUE> VALUE field(FIELD field) {
    return (VALUE) untypedField(field);
  }

  public static <FIELD extends Enum<FIELD>> Object
throwOnUndefinedField(FIELD field) throws Error {
    throw new InternalError(field + " is undefined");
  }
}

//==============================================================================================//

import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

@FunctionalInterface
public interface Cell<ELEMENT> {
  public <VALUE> VALUE select(BiFunction<? super ELEMENT, Cell<ELEMENT>, ?
extends VALUE> cons, Supplier<? extends VALUE> nil);

  public static <ELEMENT, VALUE> VALUE nil(BiFunction<? super ELEMENT,
Cell<ELEMENT>, ? extends VALUE> cons,
    Supplier<? extends VALUE> nil) {
    return nil.get();
  }

  public default int size() {
    return select(
      (element, next) -> 1 + next.size(),
      () -> 0
    );
  }

  public default Cell<ELEMENT> first(int size) {
    return Optional.of(size)
      .<Cell<ELEMENT>>map(s -> select(
        (element, next) -> s == 0
          ? nil()
          : cons(element, next.first(s - 1))
        ,
        Cell::nil
      ))
      .orElseThrow(IllegalArgumentException::new)
    ;
  }

  public default <ELEMENT2> Cell<ELEMENT2> map(Function<? super ELEMENT, ?
extends ELEMENT2> mapper) {
    return select(
      (element, next) -> Cell.cons(mapper.apply(element), next.map(mapper)),
      Cell::nil
    );
  }

  public default <ELEMENT2> Cell<ELEMENT2> flatMap(Function<? super
ELEMENT, Cell<ELEMENT2>> mapper) {
    return select(
      (element, next) -> mapper
        .apply(element)
        .select(
          Cell::cons,
          () -> next.flatMap(mapper)
        )
      ,
      Cell::nil
    );
  }

  public interface Cons<ELEMENT> {
    public ELEMENT element();
    public Cell<ELEMENT> next();

    public default <VALUE> VALUE cons(BiFunction<? super ELEMENT,
Cell<ELEMENT>, ? extends VALUE> cons, Supplier<? extends VALUE> nil) {
      return cons.apply(element(), next());
    }

    public static <ELEMENT> Cons<ELEMENT> new_(ELEMENT element,
Cell<ELEMENT> next) {
      return $.$Cons.new_(element, next);
    }

    public enum $ {
      ;

      @FunctionalInterface
      private interface $Cons<ELEMENT> extends Cons<ELEMENT>,
FunctionalField<$Cons.Field> {
        public enum Field {
          element,
          next
        }

        @Override
        public default ELEMENT element() {
          return field(Field.element);
        }

        public default Cell<ELEMENT> next() {
          return field(Field.next);
        }

        public static <ELEMENT> $Cons<ELEMENT> new_(ELEMENT element,
Cell<ELEMENT> next) {
          return field -> {
            switch (field) {
              case element: return element;
              case next: return next;
              default: return FunctionalField.throwOnUndefinedField(field);
            }
          };
        }
      }
    }
  }

  public static <ELEMENT> Cell<ELEMENT> nil() {
    return Cell::nil;
  }

  public static <ELEMENT> Cell<ELEMENT> cons(ELEMENT element, Cell<ELEMENT>
next) {
    Objects.requireNonNull(element);
    Objects.requireNonNull(next);
    return Cons.new_(element, next)::cons;
  }

  public static void main(String... arguments) {
    System.out.println(nil() == nil());  // true
    Cell<Integer> cell =
      cons(1, cons(2, cons(3, nil())))
    ;
    System.out.println(cell.size() == 3);  // true
    System.out.println(cell.first(2).size() == 2);  // true
  }
}

Samuel Dennis R. Borlongan


On Tue, Jan 28, 2014 at 6:35 PM, Remi Forax <forax at univ-mlv.fr> wrote:

> I've found a 'good' use case of why not allowing a lambda to implement a
> functional interface with a generic method is a little sad.
> http://forax.github.io/2014-01-27-8650156-the_selector_pattern.html
>
> cheers,
> Rémi
>
>
>


More information about the lambda-dev mailing list