Macro let

Introduction

This set of macros provides a functional Let capability for Synergy/DE. Let allows you to define variables with expression scope, and return the result of an operation, all in one expression. It's very useful for defining complex macros where you need to avoid multiple evaluation of arguments.

Syntax


	 let(assignments, body) => result

where:

Assignments have the syntax:


	assign(name, value)

where:

If value is a primitive, it will be automatically boxed as a Var. Assignments only have the scope of their containing let. If you reassign the same name in nested lets, the inner definition overrides the outer one until the inner expression returns.

To reference the value of one of these assignments within body, use one of the following macros:


	valueof(name) => object
	vv(name) => var
	it => object
	itv => var

Both valueof and vv access an assignment by name, but vv casts the result as a Var, while valueof returns it as an object. The it macro accesses the most recent assignment as an object, while itv casts it as a Var.

If you intend to use it or itv and don't care about the name of the variable, you can generate a unique name using one of the following macros:


	gensym => a
	genlet(value, body) => result

Gensym just creates a unique name. Genlet is a simpler version of let that uses gensym for assigning just one variable.

macros maxv, minv

For examples of how this can be useful, see the maxv and minv macros defined in synthesis.def. These macros return the greater or lesser of two values, respectively. The naive implementation of maxv, for example, would be:

.define maxv(val1,val2) fif(val1 > val2, val1, val2)

But what happens when one of the values has a side-effect or requires lengthy processing?

result = maxv(close_yearend(), minimum_fee)

In the expansion of our naive version, close_yearend() would get called twice:

result = fif(close_yearend() > minimum_fee, close_yearend(), minimum_fee)

By using let, we can insure that each argument is evaluated only once:

.define maxv(val1, val2) let(assign("val1",val1) && assign("val2",val2), fif((vv("val1") > vv("val2")), vv("val1"), vv("val2")))

which expands to:

let(assign("val1",close_yearend()) && assign("val2", minimum_fee), fif((vv("val1") > vv("val2")), vv("val1"), vv("val2")))

Now the fif macro only references values already evaluated, rather than re-evaluating the original arguments.