Lazy evaluation
From Nemerle Homepage
Contents |
Introduction
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.
Basic example
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
Infinite lists
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; }
Source
- The source code for the Nemerle.lazy and Nemerle.Lazy macros.
- Implementation of Nemerle.LazyValue class.
- Testcase utilizing lazy values.