The selector pattern

Remi Forax forax at univ-mlv.fr
Wed Jan 29 10:29:07 PST 2014


Hi Samuel,
I think I prefer this way to encode state (a 'if' instead of a 
'switch'), notice how the main is readable,
ok, you may think it's the only readable part of this code :)
I use two interfaces (in the same file) to workaround the fact that a 
lambda can not implement a generic method, with that I think the method 
get() is type safe (the suppress warning is legit here).

import java.util.function.Function;

@FunctionalInterface
interface __ extends Point {
   Object _get_(Function<Point, Object> fun);

   @Override
   @SuppressWarnings("unchecked")
   default <X> X get(Function<Point, X> fun) {
     return (X)_get_((Function<Point, Object>)fun);
   }
}

public interface Point {
   public static final Function<Point, Integer> x = Point::getX;
   public static final Function<Point, Integer> y = Point::getY;

   default int getX() { return get(x); }
   default int getY() { return get(y); }

   <X> X get(Function<Point, X> fun);

   default <X> Point with(Function<Point, ? extends X> fun, X value) {
     return (__)f -> (f == fun)? value: get(f);
   }

   static Point none() {
     return (__)f -> { throw new IllegalStateException("no value"); };
   }

   public static void main(String[] args) {
     Point point = none().with(x, 3).with(y, 4);
     System.out.println(point.get(x));
     System.out.println(point.get(y));
   }
}

cheers,
Rémi

On 01/28/2014 06:28 PM, Samuel Dennis Borlongan wrote:
> http://www.tryjava8.com/app/snippets/52e7e81be4b025782be4ec9b
> http://ideone.com/kz0B4h
> http://paste.lisp.org/display/141057
>
>
> Samuel Dennis R. Borlongan
>
>
> On Wed, Jan 29, 2014 at 1:23 AM, Sam Pullara <spullara at gmail.com 
> <mailto:spullara at gmail.com>> wrote:
>
>     It would be great if we posted code to the list with gist. Maybe
>     in addition to the email so it is easier to read :)
>
>     Sam
>
>     ---
>     Sent from Boxer | http://getboxer.com <http://bit.ly/1hRkK2W>
>     On January 28, 2014 at 7:26:06 AM PST, Samuel Dennis Borlongan wrote:
>>     Tried to create an implementation (renamed Cell because Picolisp
>>     calls it
>>     Cell) off the top of my head:
>>
>>     @FunctionalInterface
>>     public interface FunctionalField> {
>>
>>     public Object untypedField(FIELD field);
>>
>>     @SuppressWarnings("unchecked")
>>     public default VALUE field(FIELD field) {
>>     return (VALUE) untypedField(field);
>>     }
>>
>>     public static > 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 {
>>     public VALUE select(BiFunction, ?
>>     extends VALUE> cons, Supplier nil);
>>
>>     public static VALUE nil(BiFunctionCell, ? extends VALUE> cons,
>>     Supplier nil) {
>>
>>     return nil.get();
>>     }
>>
>>     public default int size() {
>>     return select(
>>     (element, next) -> 1 + next.size(),
>>     () -> 0
>>     );
>>     }
>>
>>     public default Cell first(int size) {
>>     return Optional.of(size)
>>
>>     .>map(s -> select(
>>     (element, next) -> s == 0
>>     ? nil()
>>     : cons(element, next.first(s - 1))
>>     ,
>>     Cell::nil
>>     ))
>>     .orElseThrow(IllegalArgumentException::new)
>>     ;
>>     }
>>
>>     public default Cell map(Functionextends ELEMENT2> mapper) {
>>
>>     return select(
>>     (element, next) -> Cell.cons(mapper.apply(element),
>>     next.map(mapper)),
>>     Cell::nil
>>     );
>>     }
>>
>>     public default Cell flatMap(FunctionELEMENT, Cell> mapper) {
>>
>>     return select(
>>     (element, next) -> mapper
>>     .apply(element)
>>     .select(
>>     Cell::cons,
>>     () -> next.flatMap(mapper)
>>     )
>>     ,
>>     Cell::nil
>>     );
>>     }
>>
>>     public interface Cons {
>>     public ELEMENT element();
>>     public Cell next();
>>
>>     public default VALUE cons(BiFunctionCell, ? extends VALUE> cons,
>>     Supplier nil) {
>>     return cons.apply(element(), next());
>>     }
>>
>>     public static Cons new_(ELEMENT element,
>>     Cell next) {
>>
>>     return $.$Cons.new_(element, next);
>>     }
>>
>>     public enum $ {
>>     ;
>>
>>     @FunctionalInterface
>>     private interface $Cons extends Cons,
>>
>>     FunctionalField<$Cons.Field> {
>>     public enum Field {
>>     element,
>>     next
>>     }
>>
>>     @Override
>>     public default ELEMENT element() {
>>     return field(Field.element);
>>     }
>>
>>     public default Cell next() {
>>     return field(Field.next);
>>     }
>>
>>     public static $Cons new_(ELEMENT element,
>>     Cell next) {
>>
>>     return field -> {
>>     switch (field) {
>>     case element: return element;
>>     case next: return next;
>>     default: return FunctionalField.throwOnUndefinedField(field);
>>     }
>>     };
>>     }
>>     }
>>     }
>>     }
>>
>>     public static Cell nil() {
>>     return Cell::nil;
>>     }
>>
>>     public static Cell cons(ELEMENT element, Cell
>>
>>     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 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 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