Last active
December 16, 2015 04:39
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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