Skip to content

Lazy evaluation

Alex Zimin edited this page Aug 19, 2011 · 4 revisions

Table of 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

Clone this wiki locally