Last active
January 3, 2016 02:09
-
-
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.
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
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