Lazy evaluation in one very nice feature found in programming languages with functional programming capabilities such as lisp, haskell, python etc. It mans that evaluation of variable value is delayed to the actual usage of that variable.
It means that for example if you wanted to create a list of million elements with something like this
(defn x (range 1000000)) it is not actually created, but it is just specified and when you really use that variable for the first time, for instance when you want 10th element of that list interpreter creates only first 10 elements of that list. So the first run of (take 10 x) actually creates these elements and all subsequent calls to the same function are working with already existing elements.
This is very useful because you can create infinite lists without out of memory errors.The list will be large just how much you requested. Of course, if your program is working with large data collections it can hit memory limit in the usage of these infinite lists.
On the other hand corecursion is dual to recursion. What this means? Well just like the recursive functions, which are expressed in the terms of themselves, corecursive variables are expressed in the terms of themselves.
This is best expressed on the example.
Let’s say we want list of all prime numbers. We can say that Nth prime number is the number larger than N-1th prime and not dividable by any of N-1 prime numbers before him. This is where corecursion comes into place.
When you specify the some element of list in the terms of last or some other previous elements of the same list that is called the corecursion.
For our example the code in Clojure is like this:
(def primes
(lazy-cat [2 3]
(map next-prime (rest primes))))
(defn next-prime
[last-prime]
(first (drop-while #(not (prime? %))
(range last-prime Integer/MAX_VALUE))))
(defn prime?
[num]
(every? #(not (zero? (mod num %)))
primes))
Here we defined list primes which is a concatenation of vector [2 3] and “something” that is returned from function map. The important thing is that this map is called on (rest primes) so it effectively depends on primes recursively. primes is defined with map which runs on (rest primes).
map calls provided function next-prime for each element in the list (rest primes)
The catch is to see the start of evaluation. What is (rest primes)? It is everything except the first eleement: 3, x1, x2, x3, x4……
because with lazy evaluation we can have “unknown values” which are still not evaluated.
so first time next-prime is called with argument 3 because it is the first element of (rest primes)
how next-prime works? well, it received the number 3 and it knows that next prime is larger than 3 so it creates lazy list from 3 to Integer.MAX_VALUE and then for each number it tries function prime? which checks whether the number is actually prime number. By our definition prime number is first larger number than last found prime number not dividable by any previous prime number.
so first time we call prime? with 4
primes is 2,3
then we find that 4 is dividable with 2
then we try next value from list which is 5 and we call prime? with 5
primes is 2,3
it is not dividable with 2 and 3
next-prime returns 5 as next prime number so now (rest primes) is not 2, 3, x1, x2…. but 2, 3, 5, x2…..
since we already executed map on element 3 we now call next-prime on next element which is 5
next-prime again creates list from 5 to Integer/MAX_VALUE and calls for each prime?
first value is 6
primes is 2,3, 5
6 is dividable with 2 it is not prime
next with values 7
primes is 2,3, 5
it is not dividable with any of 2, 3 and 5
so next-prime returns 7 and now list is 2, 3, 5, 7, x3, x4, ……
and by this we created list of all primes numbers and we can get get, for example list of first 20 numbers with (take 20 primes). We created only those first 20 numbers and nothing more.
next time we can call (take 21 primes) and then oly 21st element will be actually calculated. Others are calculated and stored in primes variable.
In the simmilar fashion we can create list of Fibonacci numbers
or list of factorials.
list is 1, 2, 3, 4, 5
and the factorial list is 1, 2, 6, 24, 120
the catch is to see that this can be expressed in corecursive way because 5! is 4!*5, the 6! is 6*5!
the value of element N is some function on element N-1..
in the simmilar was that prime N is the function of of previous N-1 elements
this is left as exercise