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