The selector pattern

Samuel Dennis Borlongan srborlongan at gmail.com
Wed Jan 29 20:07:30 PST 2014


I have now refactored the Cell implementation so that it uses Selector
instead of FunctionalField.
Note $Cons's use of static methods in lieu of static final variables.
Also, Selector now contains the static none method, which is used (as
Selector::none) in Cons::none and Point::none's implementations.

// Cell
http://www.tryjava8.com/app/snippets/52e9cb75e4b088ea25ce96b4
http://ideone.com/BNJgsE
http://paste.lisp.org/display/141057#4

// Point
http://www.tryjava8.com/app/snippets/52e9c98be4b088ea25ce96b2
http://ideone.com/Rr9OWL
http://paste.lisp.org/display/141057#3

Samuel Dennis R. Borlongan


On Thu, Jan 30, 2014 at 10:57 AM, Samuel Dennis Borlongan <
srborlongan at gmail.com> wrote:

> 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