I am trying to write a program that receives a stream of data as user input, runs a query on each element, and then I’m interested in counting how many of the elements the query succeeds for. To use a minimal example, here’s something that counts the even numbers in the stream:
(program entry point)
(count-evens 0 $Final)
Found $Final even numbers.
(count-evens $Current $Final)
{
(get input [$Number | $])
($Number modulo 2 into $Rem)
{
($Rem = 0)
($Current plus 1 into $Next)
(count-evens $Next $Final)
(or)
(count-evens $Current $Final)
}
(or)
($Final = $Current)
}
This could be written any number of ways, but this is one of them. If it’s easier to read, we can get out of the middle disjunction with arithmetic:
(count-evens $Current $Final)
{
(get input [$Number | $])
($Number modulo 2 into $Rem)
(1 minus $Rem into $This)
($Current plus $This into $Next)
(count-evens $Next $Final)
(or)
($Final = $Current)
}
This, as discovered, does not scale up to very many iterations: the program runs out of heap after less than 200 iterations.
If all the numbers were in a list, it would have been easy to use (accumulate 1) … (into $) to solve this:
(count-evens $List $Final)
(accumulate 1)
*($Number is one of $List)
($Number modulo 2 into $Rem)
($Rem = 0)
(into $Final)
That would presumably be more heap-efficient, but it does require the full list to be instantiated, as far as I understand it.
In order to process the values in a streaming fashion, I think one needs *(repeat forever) … (fail). However, I cannot figure out how to get this to play nicely with (accumulate 1) … (into $).
Am I trying the impossible or does anyone have good ideas?