Skip to content

Instantly share code, notes, and snippets.

@billdozr
Last active December 16, 2015 04:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save billdozr/5378679 to your computer and use it in GitHub Desktop.
Save billdozr/5378679 to your computer and use it in GitHub Desktop.
Nice post titled "List Out of Lambda" [1] written by Steve Losh, implemented here in Java 8. Building blocks of lists: 1) Functions (lambdas) 2) `true` and `false` for empty lists .... [1] http://stevelosh.com/blog/2013/03/list-out-of-lambda/
package java8.func.abstraction;
/**
* Nice post titled "List Out of Lambda" [1] written by Steve Losh,
* implemented here in Java 8.
*
* Building blocks of lists:
* * Functions (lambdas)
* * `true` and `false` for empty lists
*
* [1] http://stevelosh.com/blog/2013/03/list-out-of-lambda/
*/
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
public class ListOutOfLambdas {
@FunctionalInterface
interface SelectorFunc<T> {
T apply(Object h, ListFunc t, Boolean e);
}
@FunctionalInterface
interface ListFunc<T> {
T apply(SelectorFunc selector);
}
// Function signatures
static ListFunc emptyList;
static BiFunction<Object,ListFunc,ListFunc> prepend;
static Function<ListFunc,Object> head;
static Function<ListFunc<ListFunc>,ListFunc> tail;
static Predicate<ListFunc<Boolean>> isEmpty;
static Function<Boolean,Boolean> not;
static BiFunction<Boolean,Boolean,Boolean> and;
static BiFunction<Boolean,Boolean,Boolean> or;
static BiFunction<Function<Object,Object>, ListFunc, ListFunc<ListFunc>> map;
static BiFunction<Predicate<Object>, ListFunc, ListFunc<ListFunc>> filter;
static ListFunc zero;
static Function<ListFunc,ListFunc> inc;
static Function<ListFunc,ListFunc> dec;
static ListFunc one;
static Predicate<ListFunc> isZero;
static BiFunction<ListFunc,ListFunc,ListFunc> add;
static BiFunction<ListFunc,ListFunc,ListFunc> sub;
static BiFunction<ListFunc,ListFunc,ListFunc> mul;
static BiFunction<ListFunc,ListFunc,ListFunc> div;
static BiFunction<ListFunc,ListFunc,ListFunc> pow;
static BiFunction<ListFunc,ListFunc,ListFunc> rem;
static BiFunction<ListFunc,ListFunc,Boolean> isEqual;
static BiFunction<ListFunc,ListFunc,Boolean> lessThan;
static BiFunction<ListFunc,ListFunc,Boolean> greaterThan;
static BiFunction<ListFunc,ListFunc,Object> nth;
static BiFunction<ListFunc,ListFunc,ListFunc> drop;
static BiFunction<ListFunc,ListFunc,ListFunc> take;
static Function<ListFunc,Function<ListFunc,Function<ListFunc,ListFunc>>> slice;
static Function<ListFunc,ListFunc> length;
static {
// -- List constructs
emptyList = selector -> selector.apply(null, null, true);
prepend = (el, list) ->
selector -> selector.apply(el, list, false);
head = list -> list.apply((h, t, e) -> h);
tail = list -> list.apply((h, t, e) -> t);
isEmpty = list -> list.apply((h, t, e) -> e);
// --
// -- Boolean constructs
not = x -> !x;
and = (a, b) -> a ? b : false;
or = (a, b) -> a ? true : b;
// --
// -- Some common list functions
map = (fn, l) -> {
if (isEmpty.test(l)) {
return emptyList;
} else {
return prepend.apply(fn.apply(head.apply(l)),
map.apply(fn, tail.apply(l)));
}
};
filter = (fn, l) -> {
if (isEmpty.test(l)) {
return emptyList;
} else if (fn.test(head.apply(l))) {
return prepend.apply(head.apply(l),
filter.apply(fn, tail.apply(l)));
} else {
return filter.apply(fn, tail.apply(l));
}
};
// --
// -- Number constructs
zero = emptyList;
inc = n -> prepend.apply(emptyList, n);
dec = tail::apply;
one = inc.apply(zero);
isZero = isEmpty::test;
add = (a, b) -> isZero.test(b)
? a : add.apply(inc.apply(a), dec.apply(b));
sub = (a, b) -> isZero.test(b)
? a : add.apply(dec.apply(a), dec.apply(b));
mul = (a, b) -> isZero.test(b)
? zero : add.apply(a, mul.apply(a, dec.apply(b)));
div = (a, b) -> lessThan.apply(a, b)
? zero : inc.apply(div.apply(sub.apply(a, b), b));
pow = (a, b) -> isZero.test(b)
? one : mul.apply(a, pow.apply(a, dec.apply(b)));
rem = (a, b) -> lessThan.apply(a, b)
? a : rem.apply(sub.apply(a, b), b);
isEqual = (n, m) -> {
if (and.apply(isZero.test(n), isZero.test(m))) {
return true;
} else if (or.apply(isZero.test(n), isZero.test(m))) {
return false;
} else {
return isEqual.apply(dec.apply(n), dec.apply(m));
}
};
lessThan = (a, b) -> {
if (and.apply(isZero.test(a), isZero.test(b))) {
return false;
} else if (isZero.test(a)) {
return true;
} else if (isZero.test(b)) {
return false;
} else {
return lessThan.apply(dec.apply(a), dec.apply(b));
}
};
greaterThan = (a, b) -> lessThan.apply(b, a);
// --
// -- List functions that use numbers
nth = (l, n) -> isZero.test(n)
? head.apply(l) : nth.apply(tail.apply(l), dec.apply(n));
drop = (l, n) -> isZero.test(n)
? l : drop.apply(tail.apply(l), dec.apply(n));
take = (l, n) -> isZero.test(n)
? emptyList
: prepend.apply(head.apply(l),
take.apply(tail.apply(l), dec.apply(n)));
slice = l -> // For fun, created a curried version
start ->
end ->
take.apply(drop.apply(l, start), sub.apply(end, start));
length = l -> isEmpty.test(l)
? zero : inc.apply(length.apply(tail.apply(l)));
// --
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment