mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			436 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			436 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
library Lisp  // tiny Lisp (or rather Scheme) interpreter
 | 
						|
"Lists.fif" include
 | 
						|
variable lisp-dict
 | 
						|
{ hole dup 1 { @ execute } does create } : recursive
 | 
						|
{ atom>$ +" undefined" abort } : report-not-found
 | 
						|
// a l -- d -1 or a 0  Look up definition d of atom a in dictionary l
 | 
						|
{ { dup null? { drop false true }
 | 
						|
    { uncons -rot unpair -rot over eq?
 | 
						|
      { drop nip true true } { nip swap false } cond
 | 
						|
    } cond
 | 
						|
  } until
 | 
						|
} : lookup-in
 | 
						|
// a dict -- def
 | 
						|
{ lookup-in ' report-not-found ifnot } : lookup-or-fail
 | 
						|
{ lisp-dict @ lookup-or-fail } : lisp-dict-lookup
 | 
						|
// a d --  Defines a with definition d in dictionary lisp-dict
 | 
						|
{ pair lisp-dict @ cons lisp-dict ! } : lisp-dict-int-define
 | 
						|
{ box lisp-dict-int-define } : lisp-dict-define
 | 
						|
// a d -- Defines new a with defininition d
 | 
						|
{ over lisp-dict @ lookup-in { 2drop atom>$ +" already defined" abort }
 | 
						|
  { drop lisp-dict-int-define } cond
 | 
						|
} : lisp-dict-int-define-new
 | 
						|
{ box lisp-dict-int-define-new } : lisp-dict-define-new
 | 
						|
// a e -- Defines a with executable definition given by e
 | 
						|
{ single lisp-dict-define-new } : lisp-dict-define-exec
 | 
						|
// expr ctx def -- val
 | 
						|
{ dup first execute } : run-definition
 | 
						|
// expr ctx -- val
 | 
						|
recursive lisp-ctx-eval {
 | 
						|
  over tuple?
 | 
						|
  { over first over lisp-ctx-eval run-definition }
 | 
						|
  { over atom? { lookup-or-fail @ } { drop } cond }
 | 
						|
  cond
 | 
						|
} swap !
 | 
						|
// exp -- value
 | 
						|
{ lisp-dict @ lisp-ctx-eval } : lisp-eval
 | 
						|
// (exprs) ctx -- (vals)
 | 
						|
recursive lisp-ctx-eval-list
 | 
						|
{ over null? { drop } {
 | 
						|
  swap uncons -rot over lisp-ctx-eval -rot lisp-ctx-eval-list cons
 | 
						|
  } cond 
 | 
						|
} swap !
 | 
						|
// (exprs) ctx -- val
 | 
						|
{ null rot {
 | 
						|
  dup null? { drop nip true } {
 | 
						|
  nip uncons swap 2 pick lisp-ctx-eval swap false
 | 
						|
  } cond } until
 | 
						|
} : lisp-ctx-eval-list-last
 | 
						|
// l c -- (args)
 | 
						|
{ swap uncons nip swap lisp-ctx-eval-list } : extract-eval-arg-list
 | 
						|
{ drop uncons nip } : extract-arg-list
 | 
						|
// (x1 .. xn) e n -- x1 .. xn e
 | 
						|
{ { swap uncons rot } swap times
 | 
						|
  swap null? not abort"invalid number of arguments"
 | 
						|
} : unpack-list
 | 
						|
// l c n e -- v
 | 
						|
{ swap 2swap extract-eval-arg-list  // e n (args)
 | 
						|
  -rot unpack-list execute
 | 
						|
} : eval-exec-fixed
 | 
						|
// l c n e -- v
 | 
						|
{ 2 pick pair
 | 
						|
  swap 2swap extract-arg-list  // [e c] n (args)
 | 
						|
  -rot unpack-list unpair swap execute
 | 
						|
} : exec-fixed
 | 
						|
// l c e -- v
 | 
						|
{ -rot extract-eval-arg-list  // e (args)
 | 
						|
  swap execute
 | 
						|
} : eval-exec-list
 | 
						|
{ -rot tuck extract-arg-list  // e c (args)
 | 
						|
  swap rot execute
 | 
						|
} : exec-list
 | 
						|
// e a n --
 | 
						|
{ rot 2 {  // expr ctx def n e
 | 
						|
    rot drop eval-exec-fixed } does
 | 
						|
  lisp-dict-define-exec
 | 
						|
} : lisp-fixed-primitive
 | 
						|
{ rot 2 { rot drop exec-fixed } does lisp-dict-define-exec
 | 
						|
} : lisp-fixed-lazy-primitive
 | 
						|
// e a --
 | 
						|
{ swap 1 { nip eval-exec-list } does lisp-dict-define-exec
 | 
						|
} : lisp-primitive
 | 
						|
{ swap 1 { nip exec-list } does lisp-dict-define-exec
 | 
						|
} : lisp-lazy-primitive
 | 
						|
 | 
						|
// Uncomment next line for Fift booleans
 | 
						|
// false constant #f  true constant #t  null constant no-answer
 | 
						|
// Uncomment next line for Scheme booleans
 | 
						|
`#f constant #f  `#t constant #t  #f constant no-answer
 | 
						|
{ #f eq? } : lisp-false?
 | 
						|
{ lisp-false? 0= } : lisp-true?
 | 
						|
{ ' #t ' #f cond } : lisp-bool
 | 
						|
 | 
						|
// temp for defining a lot of primitives
 | 
						|
{ bl word atom lisp-primitive } : L:
 | 
						|
{ bl word atom swap lisp-dict-define } : L=:
 | 
						|
{ bl word atom swap lisp-fixed-primitive } : #L:
 | 
						|
{ 0 #L: } : 0L:
 | 
						|
{ 1 #L: } : 1L:
 | 
						|
{ 2 #L: } : 2L:
 | 
						|
 | 
						|
// basic primitives
 | 
						|
{ sum-list } L: +
 | 
						|
{ - } 2L: -
 | 
						|
{ dup null? { drop 1 } { ' * foldl-ne } cond } L: *
 | 
						|
{ / } 2L: /
 | 
						|
{ mod } 2L: modulo
 | 
						|
{ abs } 1L: abs
 | 
						|
{ ' min foldl-ne } L: min
 | 
						|
{ ' max foldl-ne } L: max
 | 
						|
{ true ' and foldl } L: integer-and
 | 
						|
{ false ' or foldl } L: integer-or
 | 
						|
{ 0 ' xor foldl } L: integer-xor
 | 
						|
{ not } 1L: integer-not
 | 
						|
{ = lisp-bool } 2L: =
 | 
						|
{ <> lisp-bool } 2L: <>
 | 
						|
{ < lisp-bool } 2L: <
 | 
						|
{ <= lisp-bool } 2L: <=
 | 
						|
{ > lisp-bool } 2L: >
 | 
						|
{ >= lisp-bool } 2L: >=
 | 
						|
{ eq? lisp-bool } 2L: eq?
 | 
						|
{ eqv? lisp-bool } 2L: eqv?
 | 
						|
{ equal? lisp-bool } 2L: equal?
 | 
						|
{ cons } 2L: cons
 | 
						|
{ car } 1L: car
 | 
						|
{ cdr } 1L: cdr
 | 
						|
{ cadr } 1L: cadr
 | 
						|
{ cddr } 1L: cddr
 | 
						|
{ caddr } 1L: caddr
 | 
						|
{ cdr cddr } 1L: cdddr
 | 
						|
{ concat-list-lists } L: append
 | 
						|
{ list-reverse } 1L: reverse
 | 
						|
{ list-tail } 2L: list-tail
 | 
						|
{ list-ref } 2L: list-ref
 | 
						|
{ list-member-eq } 2L: memq
 | 
						|
{ list-member-eqv } 2L: memv
 | 
						|
{ list-member-equal } 2L: member
 | 
						|
{ assq ' #f ifnot } 2L: assq
 | 
						|
{ assv ' #f ifnot } 2L: assv
 | 
						|
{ assoc ' #f ifnot } 2L: assoc
 | 
						|
{ list? lisp-bool } 1L: list?
 | 
						|
{ pair? lisp-bool } 1L: pair?
 | 
						|
{ tuple? lisp-bool } 1L: tuple?
 | 
						|
{ string? lisp-bool } 1L: string?
 | 
						|
{ integer? lisp-bool } 1L: integer?
 | 
						|
{ integer? lisp-bool } 1L: number?
 | 
						|
{ count } 1L: width
 | 
						|
{ list-length } 1L: length
 | 
						|
{ [] } 2L: tuple-ref
 | 
						|
{ first } 1L: first
 | 
						|
{ second } 1L: second
 | 
						|
{ third } 1L: third
 | 
						|
{ 3 [] } 1L: fourth
 | 
						|
{ list>tuple } 1L: list->tuple
 | 
						|
{ explode list } 1L: tuple->list
 | 
						|
null L=: null
 | 
						|
{ atom? lisp-bool } 1L: symbol?
 | 
						|
{ atom } 1L: string->symbol
 | 
						|
{ atom>$ } 1L: symbol->string
 | 
						|
{ dup #f eq? swap #t eq? or lisp-bool } 1L: boolean?
 | 
						|
#t L=: else
 | 
						|
#f L=: #f
 | 
						|
#t L=: #t
 | 
						|
{ null? lisp-bool } 1L: null?
 | 
						|
{ 0= lisp-bool } 1L: zero?
 | 
						|
{ 0> lisp-bool } 1L: positive?
 | 
						|
{ 0< lisp-bool } 1L: negative?
 | 
						|
{ 1 and 0= lisp-bool } 1L: even?
 | 
						|
{ 1 and 0<> lisp-bool } 1L: odd?
 | 
						|
{ bye } 0L: exit
 | 
						|
{ .l null } 1L: write
 | 
						|
{ lisp-eval } 1L: eval
 | 
						|
{ drop } `quote 1 lisp-fixed-lazy-primitive
 | 
						|
'nop L: list
 | 
						|
{ list>tuple } L: tuple
 | 
						|
{ list-last } L: begin
 | 
						|
{ $len } 1L: string-length
 | 
						|
{ concat-string-list } L: string-append
 | 
						|
{ $= lisp-bool } 2L: string=?
 | 
						|
{ $cmp 0< lisp-bool } 2L: string<?
 | 
						|
{ $cmp 0<= lisp-bool } 2L: string<=?
 | 
						|
{ $cmp 0> lisp-bool } 2L: string>?
 | 
						|
{ $cmp 0>= lisp-bool } 2L: string>=?
 | 
						|
{ (number) dup 1 = { drop } { ' 2drop if no-answer } cond
 | 
						|
} 1L: string->number
 | 
						|
{ (.) } 1L: number->string
 | 
						|
{ box? lisp-bool } 1L: box?
 | 
						|
{ box } 1L: box
 | 
						|
{ hole } 0L: new-box
 | 
						|
{ @ } 1L: unbox
 | 
						|
{ tuck swap ! } 2L: set-box!
 | 
						|
{ abort } 1L: error
 | 
						|
{ dup find { nip execute } { +" -?" abort } cond } : find-execute
 | 
						|
{ explode-list 1- roll find-execute } L: fift-exec
 | 
						|
{ explode-list dup 1- swap roll find-execute } L: fift-exec-cnt
 | 
						|
{ uncons swap find-execute } L: fift-exec-list
 | 
						|
// end of basic primitives
 | 
						|
forget L:  forget #L:  forget L=:
 | 
						|
forget 0L:  forget 1L:  forget 2L:
 | 
						|
 | 
						|
{ { dup tuple? ' do-quote if } list-map } : map-quote
 | 
						|
{ uncons ' cons foldr-ne map-quote
 | 
						|
  null swap cons lisp-dict @ rot run-definition
 | 
						|
} `apply lisp-primitive  // bad: should have preserved original context
 | 
						|
// e1 e2 e3 ctx
 | 
						|
{ 3 exch 3 pick lisp-ctx-eval lisp-true? ' swap if nip swap lisp-ctx-eval }
 | 
						|
`if 3 lisp-fixed-lazy-primitive
 | 
						|
// (e) ctx
 | 
						|
{ #t -rot 
 | 
						|
  { over null? { 2drop true } {
 | 
						|
    swap uncons swap 2 pick lisp-ctx-eval dup lisp-true? // v' c t v ?
 | 
						|
    { swap 2swap nip false } { -rot 2drop nip true } cond
 | 
						|
  } cond } until
 | 
						|
} `and lisp-lazy-primitive
 | 
						|
{ #f -rot
 | 
						|
  { over null? { 2drop true } {
 | 
						|
    swap uncons swap 2 pick lisp-ctx-eval dup lisp-false? // v' c t v ?
 | 
						|
    { swap 2swap nip false } { -rot 2drop nip true } cond
 | 
						|
  } cond } until
 | 
						|
} `or lisp-lazy-primitive
 | 
						|
{ lisp-false? lisp-bool } `not 1 lisp-fixed-primitive
 | 
						|
// cond-clause ctx -- v -1 or 0
 | 
						|
{ swap uncons -rot dup `else eq? {
 | 
						|
  drop lisp-ctx-eval-list-last true } {
 | 
						|
  over lisp-ctx-eval lisp-true? {
 | 
						|
  lisp-ctx-eval-list-last true } {
 | 
						|
  2drop false
 | 
						|
  } cond } cond
 | 
						|
} : eval-cond-clause
 | 
						|
// (clauses) ctx -- v
 | 
						|
{ { over null? { no-answer true } {
 | 
						|
    swap uncons -rot over eval-cond-clause } cond 
 | 
						|
  } until -rot 2drop
 | 
						|
} `cond lisp-lazy-primitive
 | 
						|
{ lisp-dict @ lookup-in { hole tuck lisp-dict-int-define } ifnot
 | 
						|
} : lisp-create-global-var
 | 
						|
// a e ctx  -- old (simple) define
 | 
						|
{ drop over atom? not abort"only a variable can be define'd"
 | 
						|
  over lisp-create-global-var swap lisp-eval swap ! 
 | 
						|
} drop // `define 2 lisp-fixed-lazy-primitive
 | 
						|
{ tuck lisp-ctx-eval rot dup atom? not abort"only a variable can be set"
 | 
						|
  rot lookup-or-fail dup @ -rot !
 | 
						|
} `set! 2 lisp-fixed-lazy-primitive
 | 
						|
// define lambda
 | 
						|
{ { dup null? { drop true true }
 | 
						|
    { uncons swap atom? { false } { drop false true } cond } cond
 | 
						|
  } until
 | 
						|
} : var-list?
 | 
						|
{ { dup null? over atom? or { drop true true }
 | 
						|
    { uncons swap atom? { false } { drop false true } cond } cond
 | 
						|
  } until
 | 
						|
} : lambda-var-list?
 | 
						|
// (quote x) -- x -1 ; else 0
 | 
						|
{ dup pair? { uncons swap `quote eq? { car true } { drop false } cond }
 | 
						|
  { drop false } cond
 | 
						|
} : is-quote?
 | 
						|
recursive match-arg-list-acc
 | 
						|
// l (vars) (args) -- ((var . arg) ...)+l -1 or ? 0
 | 
						|
{ over atom? { over `_ eq? { 2drop } { pair swap cons } cond true } { 
 | 
						|
  over null? { nip null? } { // (vars) (args)
 | 
						|
  over tuple? not { 2drop false } {
 | 
						|
  over is-quote? { eq? nip } { // (v) (a)
 | 
						|
  dup tuple? not { 2drop false } {
 | 
						|
  over count over count over <> { drop 2drop false } { // l [v] [a] n
 | 
						|
  3 roll 0 rot { // [v] [a] l i
 | 
						|
    dup 0< {
 | 
						|
      3 pick over [] swap  // [v] [a] l vi i
 | 
						|
      3 pick over [] 2swap rot // [v] [a] i l vi ai
 | 
						|
      match-arg-list-acc { // [v] [a] i l'
 | 
						|
        swap 1+ } { nip -1 } cond
 | 
						|
    } ifnot
 | 
						|
  } swap times
 | 
						|
  2swap 2drop 0>=
 | 
						|
  } cond } cond } cond } cond } cond } cond
 | 
						|
} swap !
 | 
						|
{ null -rot match-arg-list-acc } : match-arg-list
 | 
						|
// ((var . arg)...) ctx -- ctx'
 | 
						|
{ { over null? not }
 | 
						|
  { swap uncons swap unpair box pair rot cons } while
 | 
						|
  nip
 | 
						|
} : extend-ctx-by-list
 | 
						|
// ((vars) body) ctx
 | 
						|
{ swap uncons -rot 
 | 
						|
  dup lambda-var-list? not abort"invalid formal parameter list"
 | 
						|
  { // l-expr ctx' [_ body ctx (vars)]
 | 
						|
    -rot 2 pick 3 [] swap rot  // [_ body ...] (vars) ctx' l-expr
 | 
						|
    uncons nip swap lisp-ctx-eval-list  // [_ body ...] (vars) (arg-vals)
 | 
						|
    match-arg-list not abort"invalid arguments to lambda" // [_ body ...] ((var arg)...)
 | 
						|
    over third extend-ctx-by-list // [_ body ctx (vars)] ctx''
 | 
						|
    swap second swap lisp-ctx-eval-list-last
 | 
						|
  } 3 -roll 4 tuple
 | 
						|
} : make-lambda
 | 
						|
{ make-lambda } `lambda lisp-lazy-primitive
 | 
						|
// (a e) ctx -- more sophisticated (define a e)
 | 
						|
{ drop uncons swap dup atom? { // (e) a 
 | 
						|
    tuck lisp-create-global-var
 | 
						|
    swap lisp-dict @ lisp-ctx-eval-list-last swap !
 | 
						|
  } { // (e) (a v..)
 | 
						|
    uncons over atom? not abort"only variables can be define'd"  // (e) a (v..)
 | 
						|
    rot cons over lisp-create-global-var   // a ((v..) (e)) h
 | 
						|
    swap lisp-dict @ make-lambda swap !
 | 
						|
  } cond
 | 
						|
} `define lisp-lazy-primitive
 | 
						|
// ((x e) ..) ctx -- ((x.v) ..)
 | 
						|
recursive eval-assign-list
 | 
						|
{ over null? { drop } {
 | 
						|
  swap uncons swap uncons // ctx t x (e)
 | 
						|
  over atom? not abort"invalid variable name in assignment list"
 | 
						|
  3 pick lisp-ctx-eval-list-last  // ctx t x v
 | 
						|
  pair swap rot eval-assign-list cons
 | 
						|
  } cond
 | 
						|
} swap !
 | 
						|
// (((x v) ..) body) ctx  -- let construct
 | 
						|
{ swap uncons swap 2 pick eval-assign-list  // ctx body ((x v)...)
 | 
						|
  rot extend-ctx-by-list lisp-ctx-eval-list-last
 | 
						|
} `let lisp-lazy-primitive
 | 
						|
// ((x e) ..) ctx -- ctx'
 | 
						|
{ swap {
 | 
						|
  dup null? { drop true } {
 | 
						|
  uncons swap uncons  // ctx t x (e)
 | 
						|
  over atom? not abort"invalid variable name in assignment list"
 | 
						|
  3 pick lisp-ctx-eval-list-last  // ctx t x v
 | 
						|
  box pair rot cons swap false
 | 
						|
  } cond } until
 | 
						|
} : compute-let*-ctx
 | 
						|
// (((x v) ..) body) ctx  -- let* construct
 | 
						|
{ swap uncons swap rot compute-let*-ctx lisp-ctx-eval-list-last
 | 
						|
} `let* lisp-lazy-primitive
 | 
						|
// ((x e) ..) ctx -- ((h e) ..) ctx' , with x bound to h in ctx'
 | 
						|
recursive prepare-letrec-ctx {
 | 
						|
  over null? {
 | 
						|
  swap uncons swap uncons swap // ctx t (e) x
 | 
						|
  hole tuck pair swap rot cons // ctx t (x.h) (h e)
 | 
						|
  3 -roll rot cons prepare-letrec-ctx // (h e) t ctx'
 | 
						|
  -rot cons swap
 | 
						|
  } ifnot
 | 
						|
} swap !
 | 
						|
// (((x v) ..) body) ctx  -- letrec construct
 | 
						|
{ swap uncons swap rot prepare-letrec-ctx swap { // body ctx' ((h e)..)
 | 
						|
    dup null? { drop true } {
 | 
						|
    uncons -rot uncons 2 pick lisp-ctx-eval-list-last // body t ctx' h v
 | 
						|
    swap ! swap false
 | 
						|
  } cond } until
 | 
						|
  lisp-ctx-eval-list-last
 | 
						|
} `letrec lisp-lazy-primitive
 | 
						|
// (e (p e)...) ctx -- match construct
 | 
						|
{ swap uncons swap 2 pick lisp-ctx-eval swap { // ctx v ((p e)..)
 | 
						|
  dup null? { drop 2drop no-answer true } {
 | 
						|
  uncons swap uncons swap 3 pick // ctx v t e p v
 | 
						|
  match-arg-list { // ctx v t e ((x' . v')...)
 | 
						|
  2swap 2drop rot extend-ctx-by-list lisp-ctx-eval-list-last true } {
 | 
						|
  2drop false
 | 
						|
  } cond } cond } until
 | 
						|
} `match lisp-lazy-primitive
 | 
						|
//
 | 
						|
lisp-dict @ constant original-lisp-dict
 | 
						|
{ original-lisp-dict lisp-dict ! } : reset-lisp
 | 
						|
{ ' drop { lisp-eval .l cr } List-generic( } :_ LISP-EVAL-PRINT(
 | 
						|
// LISP-EVAL-PRINT((+ 3 4) (* 5 6)) computes and prints 12 and 30
 | 
						|
{ hole dup 1 { @ nip } does swap 
 | 
						|
  1 { swap lisp-eval swap ! } does 
 | 
						|
  List-generic(
 | 
						|
} :_ LISP-EVAL(
 | 
						|
// LISP-EVAL((+ 3 4) (* 5 6)) computes 12 and 30, returns only 30
 | 
						|
// /*
 | 
						|
LISP-EVAL-PRINT(
 | 
						|
  (define succ (lambda (x) (+ x 1)))
 | 
						|
  (define (twice f) (lambda (x) (f (f x))))
 | 
						|
  (define (fact n) (if (= n 0) 1 (* n (fact (- n 1)))))
 | 
						|
  (fact ((twice succ) 5))
 | 
						|
  (define compare (lambda (x y) (cond ((< x y) 'less) ((= x y) 'equal) (else 'greater))))
 | 
						|
  (compare 2 3)
 | 
						|
  (compare 7 (+ 2 3))
 | 
						|
  (define next (let ((cnt 0)) (lambda () (set! cnt (+ cnt 1)) cnt)))
 | 
						|
  (list (next) (next))
 | 
						|
  (define new-counter (lambda () (let ((x 0)) (lambda () (set! x (+ x 1)) x))))
 | 
						|
  (define c1 (new-counter))
 | 
						|
  (define c2 (new-counter))
 | 
						|
  (list (c1) (c1) (c2) (c1) (c2) (c1) (c1) (c2) (c2))
 | 
						|
  (let* ((x (+ 2 3)) (y (* x x)) (z (+ x y))) (list x y z))
 | 
						|
  (letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
 | 
						|
           (odd?  (lambda (n) (if (= n 0) #f (even? (- n 1))))))
 | 
						|
          (even? 88))
 | 
						|
  (define (len l) (if (null? l) 0 (+ 1 (len (cdr l)))))
 | 
						|
  (len '(2 3 9))
 | 
						|
  (define (len2 l) (match l (() 0) ((x . t) (+ 1 (len2 t)))))
 | 
						|
  (len2 '(2 3 9))
 | 
						|
  (define (foo x) (match x
 | 
						|
     (('zero) 0)
 | 
						|
     (('succ x) (+ (foo x) 1))
 | 
						|
     (('plus x y) (+ (foo x) (foo y)))
 | 
						|
     (('minus x y) (- (foo x) (foo y)))
 | 
						|
     (x x)))
 | 
						|
  (foo '(plus (succ (zero)) (minus (succ (succ 5)) 3)))
 | 
						|
  (define (bar x) (match x
 | 
						|
     (['zero] 0)
 | 
						|
     (['succ x] (+ (bar x) 1))
 | 
						|
     (['plus x y] (+ (bar x) (bar y)))
 | 
						|
     (['minus x y] (- (bar x) (bar y)))
 | 
						|
     (['const x] x)))
 | 
						|
  (bar '[plus [succ [zero]] [minus [succ [succ [const 5]]] [const 3]]])
 | 
						|
  (define (map f l) (letrec
 | 
						|
    ((map-f (lambda (l) (match l
 | 
						|
      (() ())
 | 
						|
      ((h . t) (cons (f h) (map-f t)))))))
 | 
						|
    (map-f l)))
 | 
						|
  (map (lambda (x) (* x (+ 2 x))) '(2 3 9))
 | 
						|
  (define (make-promise proc) (let ((result-ready? #f) (result #f))
 | 
						|
    (lambda ()
 | 
						|
      (if result-ready? result
 | 
						|
        (let ((x (proc)))
 | 
						|
	  (if result-ready? result
 | 
						|
	    (begin (set! result x) (set! result-ready? #t) result)))))))
 | 
						|
  (define (force promise) (promise))
 | 
						|
)
 | 
						|
// */
 | 
						|
// words for invoking Lisp definitions from Fift
 | 
						|
// (args) def -- val
 | 
						|
{ null rot map-quote cons lisp-dict @ rot run-definition
 | 
						|
} : invoke-lisp-definition
 | 
						|
{ atom lisp-dict-lookup 1 { @ invoke-lisp-definition }
 | 
						|
} : (invoke-lisp)
 | 
						|
{ bl word (invoke-lisp) } :: invoke-lisp
 | 
						|
// ( 2 3 ) invoke-lisp compare .l
 | 
						|
{ atom lisp-dict-lookup 2 { @ mklist-1 invoke-lisp-definition }
 | 
						|
} : (invoke-lisp-fixed)
 | 
						|
{ bl word (invoke-lisp-fixed) } :: invoke-lisp-fixed
 | 
						|
// 9 8  2 invoke-lisp-fixed compare .l
 | 
						|
{ bl word (invoke-lisp) does } : make-lisp-invoker
 | 
						|
{ bl word (invoke-lisp-fixed) does } : make-lisp-fixed-invoker
 | 
						|
// 2 make-lisp-fixed-invoker compare : compare
 | 
						|
// 3 9 compare
 | 
						|
// import Lisp definitions as Fift words
 | 
						|
{ bl word dup (invoke-lisp) does swap 0 (create) } : import-lisp
 | 
						|
{ bl word tuck (invoke-lisp-fixed) does swap 0 (create) } : import-lisp-fixed
 | 
						|
// 1 import-lisp-fixed fact
 | 
						|
// 7 fact .
 |