I started looking at Haskell and one thing that was interesting was the lazy evaluation. This allows you to write very generic functions and then chain other functions on top of it to do something on that data. This makes the programming feel more verbose and readable. Lets say if you want to get the first 10 fibonnaci number then following function
take 10 fibonnaci
is much more verbose and readable then
get_fibonnaci 10
How its done in haskell is that
fibonnaci = [fib x | x <- [1..]]
Here we are creating an infinite list and then calling a function fib
on the numbers from the list. So if you call this function alone it will try to create an infinte list of all fibonnaci numbers and your shell will go into infinite loop. But if you add take 10
before it then it will only take 10 elements from your fibonnaci series as it will not evaluate the fibonnaci
completely when its called with take 10
instead it will only call it until it meets the criteria to get only 10 items out of it. Hence it is called lazy evaluation or deffered evaluation as its lazy evaluating the function to only get what is needed.
We can actually do the same thing in C#. The yield return
creates a state machines and allows you to do the same thing but the performance in C# is not as good as in Haskell.
public static class Fibonnaci
{
public static IEnumerable<long> Series()
{
long prevN1 = 1;
long prevN2 = 1;
yield return prevN1;
yield return prevN2;
while(true)
{
long temp = prevN1 + prevN2;
prevN1 = prevN2;
prevN2 = temp;
yield return temp;
}
}
}
You might wonder that i got a bug as its a never ending loop, but you are right and wrong. If we call this function in isolation it will certainly become an infinite loop, but when I call this function chained up by other functions in LINQ library then this will work. They way to use it is
var firstTenFib = Fibonnaci.Series().Take(10)
It will do the same thing as Haskell i.e. the Take
function will call the Fibonnaci
function only 10 times and each call to the Fibonnaci
function will return the next fibonnaci number in the series. This makes it more verbose and readable and reusable code.
So if you want to get first ten even fibonnaci numbers then you do something like this
var tenEvenFib = Fibonnaci.Series().Where(i => i%2==0).Take(10);
Isn't it cool :)
But be aware the performance of this wont be good in C# as compared to Haskell.