Lambda implementation.


In mathematics lambda means a function that is not given a name. In Forth and other computer languages they are sometimes called quotations. Quotation refers to the body of a function that calls other functions that are given a name, and hence can be called by an interpreter.
Let's assume our Forth has the following mechanism available:
({) (}) brackets a piece of code and leaves an execution token, not dea. 1] Can be used outside a definition instead of :NONAME As lightweight as possible. Inside: compilation mode.
(( )) make sure dictionary space can be used between them by compiling an AHEAD, or equivalent.
([) (]) New context for definitions, maybe in the middle of a word. - tucks away onto the return stack, any data that could be spoiled by compiling something, then recovers it again In particular w.r.t. current wordlist, remove the information what word is being compiled, then restore it again. Inside: interpretation mode.
(s s) save and restore STATE.
This will allow us to add lambda's to a system, which in Forth terms are execution tokens, that can be passed to EXECUTE .
The word ,, ("multicomma") is long overdue : : ,, HERE SWAP DUP ALLOT MOVE ; We'll use it here.
First example: Let's have a smart C" , i.e. one that works in both interpret and compilation mode, then we'll unsmart it.
Remember C" AAP" leaves the address where "AAP" is stored as a brain-damaged string, one that cannot have more than 255 char's. COUNT will turn that into a regular forth constant string. (adr len), We need (( because space is allocated, but not (s because state is not changed:
: C"
    STATE @ IF (( THEN
    &" PARSE  HERE DUP C, ,,
    STATE @ IF )) THEN
    STATE @ IF POSTPONE LITERAL THEN
; IMMEDIATE

It doesn't harm to compile a jump over the string in interpret state, and LITERAL is state smart anyway so we get.
: C" ((  &" PARSE HERE DUP , ,, )) POSTPONE LITERAL ; IMMEDIATE
Note that any reference to state has disappeared, except for LITERAL which is generally accepted practice for a literal. 1]
Similarly we can have a lambda, that works in interpret state and compilation state:
Lambda has its own way with STATE so we must use (s s). We need (( too because space is allocated. Furthermore it leaves an execution token that is a literal. And of course it must compile a sequence that can be executed as code. The result is as follows.
: {
     (s
        STATE @ IF (( THEN
            ({)
; IMMEDIATE

: }
            )})
        STATE @ IF )) THEN
    s)
    STATE @ IF POSTPONE LITERAL THEN
; IMMEDIATE
Cutting the same corners this becomes
: {   (s (( ({)   ;    IMMEDIATE
: }   (}) )) s)   POSTPONE LITERAL ;    IMMEDIATE
A separate compilation stack would be ideal, otherwise care must be taken that the light weight xt left by (}) remains intact through )). Where { } leaves a constant, that can be used as a literal inside or outside of a definition, it is usefull outside of a definition. On the other hand [ ] is only useful inside a definition, but it can be used in interpret state too. This may be useful if ;) (: implements the hiding of local names of some sort.
Implementation examples (for ciforth)
\ 'TASK @ CONSTANT docol
: ({)   HERE docol , HERE CELL+ , 1 STATE ! ;
: (})   '(;) , ;      \ (;) is an alias for EXIT
For (s we need :I inlining, (Other forths can use [[ ]] if available.)
:I (s STATE @ >R ;
:I s) R> STATE ! ;

:I ((  AHEAD >R ;
:I ))  R> THEN ;
Conflating everything and saving state inside ({) which avoids inlining or the use of the return stack, we get
: {  POSTPONE AHEAD HERE docol , HERE CELL+ ,    STATE @ 1 STATE ! ;
IMMEDIATE
: }  STATE ! '(;) , POSTPONE THEN POSTPONE LITERAL ; IMMEDIATE
The consequences of having a neat { } are important. A demonstration is given in the lesson "decent looping".

Nested compilation.

Nested usage of the dictionary mechanism did not enter the picture at this stage. Up till now we didn't use [ ] , and for a good reason. If these words are to be generally useful as bracketing mechanism they must save and restore rather then setting state to a fixed value. The build up of the current definition is interrupted which need handling too.
The four brackets now allows us more powerful [ ] mechanism than is standard. By using ;) (: we create a new context for definitions, maybe in the middle of a word. Instead of the local values that are customary, we can add any type of word to the dictionary such as local tables, variables and colon definitions. We need words to isolate the latest word from the dictionary and leave its DEA, then to link that DEA again into the dictionary, as the latest. These words are as system-dependant as anything shown here. An implementation in ciforth follows.
: UNLINK-LATEST LATEST CURRENT @ >LFA DUP @ >LFA @ SWAP ! ;
: LINK-LATEST LATEST OVER >LFA ! CURRENT @ >LFA ! ;
: ;) CSP @   UNLINK-LATEST   0 STATE ! ;
: (: LINK-LATEST CSP ! ;
Now alternative square brackets can be defined. Contrary to the classical brackets they do not allow to generate a stack item, then pass it to the definition being compiled to be consumed by LITERAL. 3]
: [  (( (s ;) ;   IMMEDIATE
: ]  (: s) )) ;   IMMEDIATE

Conclusion

So we have proven the following lemma:
Adding 4 simple bracketing mechanism allows us to have all sorts of nesting imaginable. In particular using 3 of them we can have a lambda syntax that is a true literal, i.e. it is the same for interpret and compilation state and not more state-smart then a number is.

Notes


1] Sometimes called name token, to indicate that more data is available from this token than just an execution token. An objectionable name because it suggest that the only extra data is the name which is plain wrong. Think e.g. of an immediacy flag or information to find out to which wordlist the word belongs.
2] I've explained that in a system with a separate compilation stack INTERPRET can inspect whether a word leaves a literal. Then interpret can do
   ' LIT COMPILE,  COMPILE,
as needed in compilation mode.
3] This is not really a limitation. Replace
[ 122 B/BUF * ] LITERAL
by
[ 122 B/BUF * CONSTANT BUFSIZE ] BUFSIZE

  • Other Forth lectures
  • Go to the home page of Albert van der Horst