Let Expressions and Blocks - Spicery/Nutmeg GitHub Wiki

The let-syntax is used to neatly encapsulate intermediate variables, so they are only visible in the parts of the program that need to see them. It has two versions:

  • let-expression: let DECLARATIONS in EXPRESSIONS (endlet|end)
  • let-declaration: let DECLARATIONS (endlet|end)

Let Expressions

The let-expression is the commonest form of let-syntax. It is used to define some intermediate variables that are then used inside an expression. For example:

let d := sqrt( x**2, y**2 )
in
    x/d + y/d
end

Let Declarations

As an alternative the in part can be a sequence of bindings rather than a sequence of expressions:

let 
    x2 = x**2
    y2 = y**2
    d := sqrt( x2, y2 )
in
    sin := x/d
    cos := y/d
end

Modifiers

In a let-expression, the declarations can be annotated by the modifiers private, public or common with the following rules:

Note that,

block/endblock

Like a let expression, the block/endblock form is used to define some variables whilst hiding some auxiliary variables. The difference is that the hidden and exposed variables can be freely interleaved because they are marked as private or public:

  • Any variable declared as private is entirely local to that scope, as you might expect. This is the default modifier, so these are usually omitted in this context.
  • Variables declared as public are visible outside that scope, as if they were declared in the parent scope.
  • There is a third category of variables, marked as common. This is much like public but they cannot directly see any private variables. This is a modifier that is not relevant in this context but included for completeness. It is unique to Nutmug and mainly useful when defining classes.
  • As an alternative to putting private, public or common in front of the name, the declaration can be marked using the annotations @private/@public/@common.

Here is a simple example which could be written as a let:

    block
        x := ref(initial)
        public countup := fun(): x!, x! <-- $$ + 1 end
    endblock

And here is a more elaborate example that shows how you can be selective in what is and is not visible outside the block. This is more awkward to turn into a let expression.

    block
        base_value := fetch_base_value()
        public initial := calcuate_initial_value( base_value, 0 )
        x := ref(initial)
        public countup := fun(): x!, x! <-- $$ + 1 end
    end

Files as block scopes

There are a couple of other block scopes in Nutmeg. Each compiled file forms a block scope with public default. This means it is possible to have private top-level definitions that are hidden from the rest of the program. e.g.

def factorial( n ):
    fact( n, 1 )
enddef

@private
def fact( n, sofar ) =>>
    if n <= 1:
        sofar
    else:
        fact( n-1, n*sofar )
    endif
enddef

Note that the default visibility for files is public rather than private.

Classes as Block Scope

Class definitions also introduce block scopes with a default of public.

Nesting Block Scopes