The selector pattern

Samuel Dennis Borlongan srborlongan at gmail.com
Wed Jan 29 18:57:21 PST 2014


Refactored the Cell implementation so that it is less painful to look at:

http://www.tryjava8.com/app/snippets/52e9bc4ce4b088ea25ce96ae
http://ideone.com/I7sbqz
http://paste.lisp.org/display/141057#1

Also, I refactored the Point implementation so that the "bean" (Point), the
"mixin" (Selector), and the "mixed bean" ($Point) have their roles
encapsulated. As a bonus, Selector can now be used by interfaces that used
to depend on FunctionalField to implement the "bean" interface.

(I do not know what an interface with only getters and withers is called.)

http://www.tryjava8.com/app/snippets/52e9bdd2e4b088ea25ce96b0
http://ideone.com/GseqZX
http://paste.lisp.org/display/141057#2


Samuel Dennis R. Borlongan


On Thu, Jan 30, 2014 at 2:29 AM, Remi Forax <forax at univ-mlv.fr> wrote:

> 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