Skip to content

Instantly share code, notes, and snippets.

@gavinking
Last active January 3, 2016 02:09
Show Gist options
  • Save gavinking/8393540 to your computer and use it in GitHub Desktop.
Save gavinking/8393540 to your computer and use it in GitHub Desktop.
A cool way to define moving averages, demonstrating a very advanced use of reified generics.
import ceylon.collection {
LinkedList
}
import ceylon.math.float {
sin,
pi
}
"Map a function of arity `n` to a stream of values. In each
iteration `i`, the `m`th parameter of the function accepts
the `(i*n+m)`th element of the given stream as its argument."
{Result*} mapLagging<Element,Result,Collecting,Elements>(elements, collecting)
given Collecting satisfies Callable<Result,Tuple<Element,Element,Nothing>|Elements>
given Elements satisfies Tuple<Element,Element,Element[]> {
"A stream producing the elements to be mapped."
{Element*} elements;
"A function that accepts one or more elements of the
given stream, and produces a value for the resulting
stream."
Collecting collecting;
object result satisfies {Result*} {
shared actual Iterator<Result> iterator() {
value it = elements.iterator();
value list = LinkedList<Element>();
object iterator satisfies Iterator<Result> {
shared actual Result|Finished next() {
while (true) {
value next = it.next();
if (!is Finished next) {
//got a new argument
list.offer(next);
//construct an argument tuple
variable Element[] result = [];
for (e in list) {
result = [e, *result];
}
//if we have enough arguments,
//call the mapping function
if (is Elements args = result) {
list.accept(); //throw away the oldest argument
return collecting(*args);
}
}
else {
//run out of potential arguments
return finished;
}
}
}
}
return iterator;
}
}
return result;
}
"Arithmetic mean of two values."
Float arithmeticMean2(Float x, Float y)=>(x+y)/2;
"Arithmetic mean of four values."
Float arithmeticMean4(Float w, Float x, Float y, Float z)=>(w+x+y+z)/4;
"Geometric mean of three values."
Float geometricMean3(Float x, Float y, Float z)=>(x*y*z)^(1.0/3);
void testMovingAverages() {
value timeSeries = { for (i in 0..30) sin(i.float*pi/8)+i/10.0 };
print(mapLagging(timeSeries, arithmeticMean2));
print(mapLagging(timeSeries, arithmeticMean4));
print(mapLagging(timeSeries, geometricMean3));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment