#lang racket |
|
; (walk-over-expression expr) |
|
; recursor, walk over and accumulate results, in this case just reconstruct |
; the expression |
(define walk-over-r |
(lambda (accum expr) |
(cond |
( (not (list? expr)) |
; handle simple atomic term here |
expr |
) |
( (null? expr) |
; handle empty list here |
accum |
) |
(#t |
; handle list here |
(map (lambda (e) (walk-over-r '() e)) expr) |
) |
) |
|
)) |
|
(define walk-over |
(lambda (expr) |
(walk-over-r '() expr) |
)) |
|
(walk-over '()) |
(walk-over 'a) |
(walk-over '(a b c)) |
(walk-over '(lambda () x)) |
(walk-over '(lambda (x) x)) |
(walk-over '(lambda (x y) x)) |
(walk-over '(lambda (x) (lambda (y) x y))) |
(walk-over '(lambda (x) (lambda (y) x y (lambda (z) (lambda (y) x y))))) |
#lang racket |
|
; Example of threading state through a recursively decomposed problem. |
|
; Problem: go through a list (utimately an expression to be transformed) |
; and sequentially number each token encountered in the left to right |
; depth-first traversal of the list. |
; |
; For example: |
; (walk-over '( (a b ( c d ) e ) f ( g h (i ( j k ( l m ) ) ) ) n ) ) |
; geneates this result: |
; ((a-0 b-1 (c-2 d-3) e-4) f-5 (g-6 h-7 (i-8 (j-9 k-10 (l-11 m-12)))) n-13) |
|
; The recursor takes state-in (a list) and an expression and returns |
; a list (state-out result) |
; |
; (walk-over-expression-r state-in expr) -> (state-out result) |
|
; The state is very simple, consisting of a 1-element list, where the |
; element is the sequence number for the next symbol. |
|
(define walk-over-r |
(lambda (state-in expr) |
(cond |
( (not (list? expr)) |
; handle simple atomic term here, use new symbol number and update |
; the next symbol number |
(list (list (+ 1 (first state-in))) |
(string->symbol (string-append (symbol->string expr) "-" |
(number->string (first state-in)) ) )) |
) |
(#t |
; handle list here, use fold to thread previous results |
(foldl |
; e is the current element to be processed |
; fold-state is a list (state-in current-fold-results) |
|
(lambda (e fold-state) |
(let ( [ e-result (walk-over-r (first fold-state) e) ] ) |
; now construct new fold state to pass along consisting of |
; updated state and appending modified expression to the |
; current-fold-results |
(list (first e-result) |
(append (second fold-state) (list (second e-result))) |
) |
) |
) |
|
(list state-in '()) ; initial state and result |
expr |
) |
) |
) |
) |
) |
|
(define walk-over |
(lambda (expr) |
(second (walk-over-r '(0) expr)) |
|
; To see what the final state is, use this variant |
; (walk-over-r '(0) expr) |
)) |
|
|
|
(walk-over '()) |
(walk-over 'a) |
(walk-over '(a b c)) |
(walk-over '(lambda () x)) |
(walk-over '(lambda (x) x)) |
(walk-over '(lambda (x y) x)) |
(walk-over '(lambda (x) (lambda (y) x y))) |
(walk-over '(lambda (x) (lambda (y) x y (lambda (z) (lambda (y) x y))))) |
(walk-over '( (a b ( c d ) e ) f ( g h (i ( j k ( l m ) ) ) ) n ) ) |
#lang racket |
|
; First cut at evaluator for simple arithmetic expression trees. In this |
; version we do not need any global state. But in the next version with |
; variables we will. |
|
(define evaluate-expression-r |
(lambda (state-in expr) |
(cond |
( (not (list? expr)) |
; handle simple atomic term here, use new symbol number and update |
; the next symbol number |
(list state-in expr) |
) |
(#t |
; handle list here, use fold to thread previous results |
; fold-state is a list of threaded state (unused) and a list |
; containing the value of the expressions that are the subtrees |
; of the current expression. There should be two values on the |
; latter list when the recursion encounters an operation |
|
(foldl |
(lambda (e fold-state) |
(let ( [ e-result (evaluate-expression-r (first fold-state) e) ] ) |
; now pass on state and augmented result |
(list (first e-result) ; state-out |
(if (equal? e 'PLUS) |
; if at a plus, the first 2 items on the previous |
; results list are the values to be added. |
(+ (first (second fold-state)) |
(second (second fold-state))) |
|
; If not a plus, we have an expression evaluation |
; result to save. |
(append (second fold-state) (list (second e-result))) |
) |
) |
) |
) |
|
(list state-in '()) ; initial state and result |
expr |
) |
) |
) |
) |
) |
|
(define evaluate-expression |
(lambda (expr) |
(second (evaluate-expression-r '() expr)) |
)) |
|
|
|
(evaluate-expression 1) |
(evaluate-expression '( (42 10 PLUS) (1 3 PLUS) PLUS)) |
(evaluate-expression |
'( ((42 10 PLUS) (1 3 PLUS) PLUS) ((2 4 PLUS) (8 16 PLUS) PLUS) PLUS)) |
|
And here it is with extensions for variables.
#lang racket |
|
; Evaluator for simple arithmetic expression trees. In this |
; version we use global state containing a hash to keep track |
; of current variable values. |
|
; the global state is a list consisting of one element: an immutable hash |
|
(define evaluate-expression-r |
(lambda (state-in expr) |
(cond |
( (not (list? expr)) |
; handle simple atomic term here, use new symbol number and update |
; the next symbol number |
(list state-in (lookup-value state-in expr)) |
) |
(#t |
; handle list here, use fold to thread previous results |
; fold-state is a list of state followed by a list containing |
; the value of the expressions that are the subtrees of the |
; current expression. There should be two values on the latter |
; list when the recursion encounters an operation |
|
(foldl |
(lambda (e fold-state) |
(let ( [ e-result (evaluate-expression-r (first fold-state) e) ] ) |
; now pass on state and augmented result |
(cond |
( (equal? e 'PLUS) |
; if at a plus, the first 2 items on the previous |
; results list are the values to be added. |
(list (first e-result) |
(+ (first (second fold-state)) |
(second (second fold-state))) |
) |
) |
|
( (equal? e 'ASSIGN) |
; if at an assignment, the first element is |
; assigned to be the value of the |
; variable in the second list element. |
(list (list (dict-set (first (first e-result)) |
(second (second fold-state)) |
(first (second fold-state))) ) |
(first (second fold-state)) ) |
) |
|
(#t |
; If not a plus or assignment, we have an |
; expression evaluation result to save. |
(list (first e-result) |
(append (second fold-state) |
(list (second e-result))) |
) |
) |
) |
|
) |
) |
|
(list state-in '()) ; initial state and result |
expr |
) |
) |
) |
) |
) |
|
(define evaluate-expression |
(lambda (expr) |
(second (evaluate-expression-r (list (make-immutable-hash '()) ) expr)) |
)) |
|
; look up value of identifier exp in the hash contained in the state, |
; if not present return the identifier |
(define lookup-value |
(lambda (state-in exp) |
(hash-ref (first state-in) exp exp) |
) |
) |
|
|
(evaluate-expression 1) |
(evaluate-expression '( (42 10 PLUS) (1 3 PLUS) PLUS)) |
(evaluate-expression |
'( ((42 10 PLUS) (1 3 PLUS) PLUS) ((2 4 PLUS) (8 16 PLUS) PLUS) PLUS)) |
(evaluate-expression '( (2 A ASSIGN) (A A PLUS) PLUS ) ) |
(evaluate-expression |
'( ( 100 ( (((40 2 PLUS) A ASSIGN) A PLUS) B ASSIGN) PLUS ) (B A PLUS) PLUS) ) |
|
; and this surprising one |
(evaluate-expression '( (2 1 ASSIGN) 1 PLUS ) ) |
|
;(define h (make-immutable-hash '())) |
;(define h1 (dict-set h 'a 21)) |
;(define h2 (dict-set h1 'b 42)) |
;(hash-ref h1 'a 99) |
;(hash-ref h1 'b 99) |
;(hash-ref h2 'b 99) |