-
Notifications
You must be signed in to change notification settings - Fork 89
Lazy evaluation
Sometimes we know that a given expression will be evaluated only on some (maybe rare) computation paths. When it is just a simple operation we do not care about it - the more important fact for us is that declaring a variable initialized with this expression is making our code cleaner. But when computing a given expression is expensive in performance, we would like it to be evaluated only when needed.
This is one of the applications for lazy evaluation.
using System;
using Nemerle;
class M
{
static foo ([Lazy] x : int, y : bool) : void
{
if (y)
{
Console.WriteLine(x);
Console.WriteLine(x);
}
else
Console.WriteLine("nothing");
}
static SideEffect : int
{
get
{
Console.WriteLine("somebody is fetching me");
1
}
}
public static Main() : void
{
def laz = lazy(SideEffect + 1);
foo(laz, false);
foo(laz, true);
}
}
will print
nothing somebody is fetching me 2 2
Lazy evaluation allows us to implement infinite lists easily. The node of our list presented below has two fields - current value in Val and reference to the next element in Next. But the instance contained in Next is a lazy value, so it will be evaluated only when requested.
class InfList
{
public Val : int;
public Next : LazyValue[InfList];
public this(v : int)
{
Val = v;
Next = lazy(InfList(v + 1));
}
}
Note that we can use InfList just like it was a standard list. We can iterate over it in a loop and everytime when Next is accessed, the new node is created and memoized.
mutable inflist = InfList(0);
repeat (10)
{
Nemerle.IO.printf("%d ", inflist.Val);
inflist = inflist.Next;
}
- The source code for the
Nemerle.lazy
andNemerle.Lazy
macros. -
Implementation of
Nemerle.LazyValue
class. - Testcase utilizing lazy values.