all repos — mn @ 62192baa78534dfe25eaf16954e3c695dc36ccbd

A truly minimal concatenative programming language.

docs/learn-definitions.md

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
-----
content-type: "page"
title: "Learn: Definitions"
-----
{@ _defs_.md || 0 @}

Being a concatenative language, {{m}} does not really need named parameters or variables: symbols just pop elements off the main stack in order, and that's normally enough. There is however one small problem with the traditional concatenative paradigm; consider the following program for example:

     dup 
     () cons "Compiling on $#..." swap interpolate puts pop
     () cons "nim --os:$# c test.nim" swap interpolate run

This program takes an operating system indetifier (windows, linux, osx) and attempts to build the file **test.nim** for it. Sure, it is remarkable that no variables are needed for such a program, but it is not very readable: because no variables are used, it is often necessary to make copies of elements and push them to the end of the stack -- that's what the {#link-symbol||dup#} and {#link-symbol||swap#} are used for.

The good news is that you can use the {#link-symbol||let#} symbol to define new symbols, and symbols can also be set to literals of course.

Consider the following program:

     (os) let
     "Compiling on $#..." (os) interpolate puts pop
     "nim --os:$# c test.nim" (os) interpolate run

In this case, the first element on the stack is saved to a symbol called **os**, which is then used whenever needed in the rest of the program.


## Lexical scoping and binding

mn, like many other programming languages, uses [lexical scoping](https://en.wikipedia.org/wiki/Scope_\(computer_science\)#Lexical_scope_vs._dynamic_scope) to resolve symbols.

Consider the following program:


     4 (a) let
     ( 
       a 3 + (a) let
       (
          a 1 + (a) let
          (a dup * (a) let) dequote
       ) dequote
     ) dequote

...What is the value of the symbol `a` after executing it? 

Simple: `4`. Every quotation defines its own scope, and in each scope, a new variable called `a` is defined. In the innermost scope containing the quotation `(a dup * (a) let)` the value of `a` is set to `64`, but this value is not propagated to the outer scopes. Note also that the value of `a` in the innermost scope is first retrieved from the outer scope (8).

If we want to change the value of the original `a` symbol defined in the outermost scope, we have to use the {#link-symbol||bind#}, so that the program becomes the following:

     4 (a) let ;First definition of the symbol a
     (
       a 3 + (a) bind ;The value of a is updated to 7.
       (
         a 1 + (a) bind ;The value of a is updated to 8
         (a dup * (a) bind) dequote ;The value of a is now 64
       ) dequote
     ) dequote