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