Table of Contents

Introduction

Sometimes we know that 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 variable initialized with this expression is making our code cleaner. But when computing 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
 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 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