All Articles

Eager Evaluation and Macros

Eager evaluation is when an expression is evaluated as soon as it is assigned to a variable. Most languages are eagerly evaluated because any side-effects occur immediately, rather than prolonging them along execution.

However, there are situations where eager evaluation works against a program.

Boolean Operators

Suppose there is a need for implementing new versions of the boolean operators: and, or.

(define (my-or p q)
  (if p #t q))

; (my-or #t (/ 0 0)) ; => ERROR

Implementing my-or is unachievable because short-circuiting does not occur due to eager evaluation; the illegal operation division by zero takes precedence. Similarly, the same situation is present when implementing my-and.

(define (my-and p q)
  (if (not p) #f q))

; (my-and #f (/ 1 0)) => ERROR

The errors in both these functions are produced due to runtime exceptions. To solve this, Racket macros will come in handy.

Using Macros

Macros are patterns in code which get replaced by predetermined code expressions during compile time. Whenever replacement occurs, the term Macro Expansion is used to encapsulate this idea. The best way to demonstrate this, is by implementing the boolean operators as macros.

(define-syntax my-or
  (syntax-rules ()
    [(my-or p q) ; Whenever Racket finds this syntax...
     (if p #t q)])) ; replace it with this.

; (my-or #t (/ 0 0)) ; macro gets expanded to...
; (if #t #t (/ 0 0)) ; this expression.

In this example, my-or is implemented as a Racket macro. Whenever my-or is used, it gets pattern-matched and replaced with the specified if-else statement which implements my-or. Like-wise, my-and can be implemented in the same way.

(define-syntax my-and
  (syntax-rules ()
    [(my-and p q)
     (if (not p) #f q)]))

; (my-and #f (/ 0 0)) ; macro gets expanded to...
; (if (not #f) #f (/ 0 0)) ; this expression.

Just like before, my-and is a macro, and its implementation is an if-else statement that replaces any occurrence of my-and.

Since pattern-matching and macro expansion occurs during compile time, eager evaluation is prevented from taking place; this allows new implementations of boolean operators.

Summary

Eager evaluation prevents programs from passing arguments which yield errors, in the case of boolean expressions, the program cannot implement short-circuiting. To avoid this, macros can be used whenever our program needs to delay the execution of an expression, as illustrated by implementing the and and or boolean operators.

Epilogue

Macros were useful for implementing boolean operators, but there is a downside to them. A function can be called 100 times and still occupy constant space. Macros on the other hand, can be pattern matched 100 times in code, and increase the size of the program 100 times the size of the macro. This is important when choosing whether or not an operation should be implemented as a macro or function.

Extra links
Published 6 Dec 2015