Compare commits
6 Commits
main
...
lazy-exten
Author | SHA1 | Date |
---|---|---|
Oliver Payne | 9d454b2a26 | |
Oliver Payne | 6abfa8e373 | |
Oliver Payne | 59ae77997d | |
Oliver Payne | cd8884445e | |
Oliver Payne | f93c533f54 | |
Oliver Payne | a6d3fd7f81 |
|
@ -0,0 +1,60 @@
|
||||||
|
#lang sicp
|
||||||
|
|
||||||
|
(#%require "leval.rkt")
|
||||||
|
(#%require "test-eval.rkt")
|
||||||
|
|
||||||
|
(define (program delay)
|
||||||
|
`((define count 0)
|
||||||
|
(define (id ,(qualify-arg 'x delay))
|
||||||
|
(set! count (+ count 1)) x)
|
||||||
|
(define (square ,(qualify-arg 'x delay))
|
||||||
|
(* x x))
|
||||||
|
(square (id 10))
|
||||||
|
count))
|
||||||
|
|
||||||
|
(define (input-sequence val count)
|
||||||
|
(cons 'list
|
||||||
|
(let loop ((n count))
|
||||||
|
(if (= n 0) '()
|
||||||
|
(cons val (loop (- n 1)))))))
|
||||||
|
|
||||||
|
(define (map-program length delay)
|
||||||
|
`((define (f ,(qualify-arg 'x delay))
|
||||||
|
(+ x (sqrt x)))
|
||||||
|
(define input
|
||||||
|
,(input-sequence 5 length))
|
||||||
|
(define (map ,(qualify-arg 'f delay)
|
||||||
|
,(qualify-arg 'x delay))
|
||||||
|
(if (null? x) '()
|
||||||
|
(cons (f (car x))
|
||||||
|
(map f (cdr x)))))
|
||||||
|
(map f input)))
|
||||||
|
|
||||||
|
|
||||||
|
(#%require (only racket/base module+))
|
||||||
|
(#%require rackunit)
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
;; With the normal lazy evaluator, square evaluates id twice
|
||||||
|
(check-equal? (lazy-eval-program (program 'lazy)) 2)
|
||||||
|
;; With the memoizing evaluator, the first call to id is memoized,
|
||||||
|
;; so another call is not needed.
|
||||||
|
(check-equal? (lazy-eval-program (program 'lazy-memo)) 1))
|
||||||
|
|
||||||
|
(module+ timing
|
||||||
|
|
||||||
|
;; Map needs to re-evaluate the procedure f for each element of the
|
||||||
|
;; input for lazy evaluation. If memoized, this is only evaluated once.
|
||||||
|
(define lazy-map (time-proc 100 (lambda () (lazy-eval-program
|
||||||
|
(map-program 100 'lazy)))))
|
||||||
|
(define lazy-memo-map (time-proc 100 (lambda () (lazy-eval-program
|
||||||
|
(map-program 100 'lazy-memo)))))
|
||||||
|
(display `("Map: lazy " ,lazy-map " lazy-memo " ,lazy-memo-map " speed-up "
|
||||||
|
,(/ lazy-map lazy-memo-map)))
|
||||||
|
|
||||||
|
;; Gives ~16x speedup.
|
||||||
|
)
|
||||||
|
|
||||||
|
;; In general, performance for the memoizing evaluator should be
|
||||||
|
;; much better when multiple references are made to the result of
|
||||||
|
;; evaluating a procedure.
|
|
@ -0,0 +1,95 @@
|
||||||
|
;; for-each is defined:
|
||||||
|
;; (define (for-each (proc lazy) (items lazy))
|
||||||
|
;; (if (null? items)
|
||||||
|
;; 'done
|
||||||
|
;; (begin (proc (car items))
|
||||||
|
;; (for-each proc (cdr items)))))
|
||||||
|
|
||||||
|
|
||||||
|
;; Part a: using the eval-sequence from leval handles sequenced side
|
||||||
|
;; effects in for-each correctly. The example evaluates as follows:
|
||||||
|
;; (for-each (lambda (x) (newline) (display x))
|
||||||
|
;; (list 57 321 88))
|
||||||
|
|
||||||
|
;; (begin ((lambda (x) (newline) (display x)) 57)
|
||||||
|
;; (begin ((lambda (x) (newline) (display x)) 321)
|
||||||
|
;; (begin ((lambda (x) (newline) (display x)) 88))))
|
||||||
|
|
||||||
|
;; The first begin evaluates the first argument, which is an
|
||||||
|
;; application, so it forces the procedure and delays its argument.
|
||||||
|
;; Thus we have:
|
||||||
|
|
||||||
|
;; ((lambda (x) (newline) (display x)) '(thunk 57))
|
||||||
|
|
||||||
|
;; newline and display are both native procedures, so their arguments
|
||||||
|
;; are forced, and 57 is displayed. The rest of the values follow
|
||||||
|
;; similarly. The reason the normal-eval sequence works is that the
|
||||||
|
;; procedure being applied for its side effect calls a primitive
|
||||||
|
;; procedure.
|
||||||
|
|
||||||
|
;; Part b:
|
||||||
|
|
||||||
|
;; Define p1 and p2
|
||||||
|
|
||||||
|
;; (define (p1 (x lazy))
|
||||||
|
;; (set! x (cons x '(2)))
|
||||||
|
;; x)
|
||||||
|
|
||||||
|
;; (define (p2 (x lazy))
|
||||||
|
;; (define (p (e lazy))
|
||||||
|
;; e
|
||||||
|
;; x)
|
||||||
|
;; (p (set! x (cons x '(2)))))
|
||||||
|
|
||||||
|
;; Using the original evaluator:
|
||||||
|
|
||||||
|
;; (p1 1)
|
||||||
|
;; -> (set! x (cons 1 '(2))) x
|
||||||
|
;; ->(1 2)
|
||||||
|
|
||||||
|
;; because cons is primitive, so x is forced
|
||||||
|
|
||||||
|
;; (p2 1)
|
||||||
|
;; -> (p '(thunk set! x (cons x '(2))) 1)
|
||||||
|
;; -> 1
|
||||||
|
|
||||||
|
;; because nothing ever uses the argument to p, it is never forced.
|
||||||
|
|
||||||
|
;; An alternative eval-sequence that forces all expressions other than
|
||||||
|
;; the last one to ensure all side effects are carried out.
|
||||||
|
;; (define (eval-sequence* exps env)
|
||||||
|
;; (cond ((last-exp? exps) (eval (first-exp exps) env))
|
||||||
|
;; (else (actual-value (first-exp exps) env)
|
||||||
|
;; (eval-sequence* (rest-exps exps) env))))
|
||||||
|
|
||||||
|
;; Using this:
|
||||||
|
;; (p1 1)
|
||||||
|
;; -> (1 2)
|
||||||
|
|
||||||
|
;; as before
|
||||||
|
|
||||||
|
;; (p2 1)
|
||||||
|
;; -> (p '(thunk set! x (cons x '(2))))
|
||||||
|
;; -> (actual-value '(thunk set! x (cons x '(2)))) (actual-value x)
|
||||||
|
;; -> (1 2)
|
||||||
|
|
||||||
|
|
||||||
|
;; Part c:
|
||||||
|
|
||||||
|
;; Using eval-sequence*
|
||||||
|
|
||||||
|
;; (for-each (lambda (x) (newline) (display x))
|
||||||
|
;; (list 57 321 88))
|
||||||
|
|
||||||
|
;; -> (begin ((lambda (x) (newline) (display x)) 57)
|
||||||
|
;; (begin ((lambda (x) (newline) (display x)) 321)
|
||||||
|
;; (begin ((lambda (x) (newline) (display x)) 88))))
|
||||||
|
|
||||||
|
;; This evaluates as for eval-sequence because the procedure only has
|
||||||
|
;; native procedures which are forced anyway, so there is no
|
||||||
|
;; difference between the two options.
|
||||||
|
|
||||||
|
;; Part d: I prefer eval-sequence*, Cy's approach, as sequences are
|
||||||
|
;; used for side effects (since only the value of the final
|
||||||
|
;; expression is returned). So ensuring that side-effects are handled
|
||||||
|
;; correctly seems like a better option.
|
|
@ -166,6 +166,7 @@
|
||||||
(list '/ /)
|
(list '/ /)
|
||||||
(list '< <)
|
(list '< <)
|
||||||
(list '> >)
|
(list '> >)
|
||||||
|
(list 'sqrt sqrt)
|
||||||
(list 'newline newline)
|
(list 'newline newline)
|
||||||
(list 'display display)
|
(list 'display display)
|
||||||
))
|
))
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
|
|
||||||
;;;; OMP: modified to work with racket and to fit with existing code
|
;;;; OMP: modified to work with racket and to fit with existing code
|
||||||
|
|
||||||
|
;;;; This evaluator uses the modifications of exercise 4.31: arguments
|
||||||
|
;;;; can be strict, lazy or lazy with memoization. To specify a
|
||||||
|
;;;; procedure, strict in x, lazy in y and lazy with memoization in z:
|
||||||
|
;;;; (define (f x (y 'lazy) (z 'lazy-memo))).
|
||||||
|
|
||||||
(#%require racket/trace)
|
(#%require racket/trace)
|
||||||
(#%require "syntax.rkt")
|
(#%require "syntax.rkt")
|
||||||
(#%require "environment.rkt")
|
(#%require "environment.rkt")
|
||||||
|
@ -52,7 +57,10 @@
|
||||||
(procedure-body procedure)
|
(procedure-body procedure)
|
||||||
(extend-environment
|
(extend-environment
|
||||||
(procedure-parameters procedure)
|
(procedure-parameters procedure)
|
||||||
(list-of-delayed-args arguments env) ; changed
|
(list-of-qualified-args
|
||||||
|
arguments
|
||||||
|
(procedure-delays procedure)
|
||||||
|
env) ; changed
|
||||||
(procedure-environment procedure))
|
(procedure-environment procedure))
|
||||||
lazy-eval))
|
lazy-eval))
|
||||||
(else
|
(else
|
||||||
|
@ -66,12 +74,18 @@
|
||||||
(list-of-arg-values (rest-operands exps)
|
(list-of-arg-values (rest-operands exps)
|
||||||
env))))
|
env))))
|
||||||
|
|
||||||
(define (list-of-delayed-args exps env)
|
(define (list-of-qualified-args exps delays env)
|
||||||
(if (no-operands? exps)
|
(if (no-operands? exps)
|
||||||
'()
|
'()
|
||||||
(cons (delay-it (first-operand exps) env)
|
(cons
|
||||||
(list-of-delayed-args (rest-operands exps)
|
(let ((delay (first-delay delays)))
|
||||||
env))))
|
(if (eq? delay 'strict)
|
||||||
|
(lazy-eval (first-operand exps) env)
|
||||||
|
(delay-it (first-operand exps) env delay)))
|
||||||
|
(list-of-qualified-args
|
||||||
|
(rest-operands exps)
|
||||||
|
(rest-delays delays)
|
||||||
|
env))))
|
||||||
|
|
||||||
(define (lazy-eval-if exp env)
|
(define (lazy-eval-if exp env)
|
||||||
(if (true? (actual-value (if-predicate exp) env))
|
(if (true? (actual-value (if-predicate exp) env))
|
||||||
|
@ -98,20 +112,17 @@
|
||||||
|
|
||||||
;;; Representing thunks
|
;;; Representing thunks
|
||||||
|
|
||||||
;; non-memoizing version of force-it
|
(define (delay-it exp env method)
|
||||||
|
(cond ((eq? method 'lazy-memo)
|
||||||
;; (define (force-it obj)
|
(make-memo-thunk exp env))
|
||||||
;; (if (thunk? obj)
|
((eq? method 'lazy)
|
||||||
;; (actual-value (thunk-exp obj) (thunk-env obj))
|
(make-thunk exp env))
|
||||||
;; obj))
|
(else
|
||||||
|
(error ("Unknown delay type -- DELAY-IT" method)))))
|
||||||
(define (delay-it exp env)
|
|
||||||
(make-thunk exp env))
|
|
||||||
|
|
||||||
;; memoizing version of force-it
|
|
||||||
|
|
||||||
|
;; memo-thunks created by are memoized on forcing. thunks are not.
|
||||||
(define (force-it obj)
|
(define (force-it obj)
|
||||||
(cond ((thunk? obj)
|
(cond ((memo-thunk? obj)
|
||||||
(let ((result (actual-value
|
(let ((result (actual-value
|
||||||
(thunk-exp obj)
|
(thunk-exp obj)
|
||||||
(thunk-env obj))))
|
(thunk-env obj))))
|
||||||
|
@ -121,7 +132,17 @@
|
||||||
result))
|
result))
|
||||||
((evaluated-thunk? obj)
|
((evaluated-thunk? obj)
|
||||||
(thunk-value obj))
|
(thunk-value obj))
|
||||||
|
((thunk? obj)
|
||||||
|
(actual-value
|
||||||
|
(thunk-exp obj)
|
||||||
|
(thunk-env obj)))
|
||||||
(else obj)))
|
(else obj)))
|
||||||
|
|
||||||
|
(#%require (only racket/base module+))
|
||||||
|
(module+ test
|
||||||
|
(#%require rackunit)
|
||||||
|
(define env (setup-environment))
|
||||||
|
(check-equal? (force-it (delay-it '(+ 1 1) env 'lazy)) 2)
|
||||||
|
(check-equal? (force-it (delay-it '(+ 1 1) env 'lazy-memo)) 2))
|
||||||
|
|
||||||
'LAZY-EVALUATOR-LOADED
|
'LAZY-EVALUATOR-LOADED
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#lang sicp
|
#lang sicp
|
||||||
|
|
||||||
|
(#%require racket/trace)
|
||||||
|
|
||||||
(#%provide (all-defined))
|
(#%provide (all-defined))
|
||||||
|
|
||||||
(define (self-evaluating? exp)
|
(define (self-evaluating? exp)
|
||||||
|
@ -90,6 +92,11 @@
|
||||||
(define (rest-operands ops) (cdr ops))
|
(define (rest-operands ops) (cdr ops))
|
||||||
(define (last-operand? ops) (null? (rest-operands ops)))
|
(define (last-operand? ops) (null? (rest-operands ops)))
|
||||||
|
|
||||||
|
(define (no-delays? ops) (null? ops))
|
||||||
|
(define (first-delay ops) (car ops))
|
||||||
|
(define (rest-delays ops) (cdr ops))
|
||||||
|
(define (last-delay? ops) (null? (rest-delays ops)))
|
||||||
|
|
||||||
;; cond (including recipient clause for exercise 4.5)
|
;; cond (including recipient clause for exercise 4.5)
|
||||||
(define (cond? exp) (tagged-list? exp 'cond))
|
(define (cond? exp) (tagged-list? exp 'cond))
|
||||||
(define (cond-clauses exp) (cdr exp))
|
(define (cond-clauses exp) (cdr exp))
|
||||||
|
@ -318,16 +325,31 @@
|
||||||
(unless-consequent exp)
|
(unless-consequent exp)
|
||||||
(unless-alternative exp)))
|
(unless-alternative exp)))
|
||||||
|
|
||||||
(define (make-procedure parameters body env)
|
;; Exercise 4.31: procedure parameters can be qualified by 'lazy or
|
||||||
(list 'procedure parameters body env))
|
;; 'lazy-memo. In either case, the parameter will be a 2-element list
|
||||||
|
;; with the parameter name first and the delay second. Normal
|
||||||
|
;; single-element parameters are taken to be strictly evaluated.
|
||||||
|
(define (make-procedure qualified-parameters body env)
|
||||||
|
(define (parameter qualified-parameter)
|
||||||
|
(if (pair? qualified-parameter)
|
||||||
|
(car qualified-parameter)
|
||||||
|
qualified-parameter))
|
||||||
|
(define (delay qualified-parameter)
|
||||||
|
(if (pair? qualified-parameter)
|
||||||
|
(cadr qualified-parameter)
|
||||||
|
'strict))
|
||||||
|
(list 'procedure
|
||||||
|
(map parameter qualified-parameters)
|
||||||
|
(map delay qualified-parameters)
|
||||||
|
body env))
|
||||||
|
|
||||||
(define (compound-procedure? p)
|
(define (compound-procedure? p)
|
||||||
(tagged-list? p 'procedure))
|
(tagged-list? p 'procedure))
|
||||||
|
|
||||||
|
|
||||||
(define (procedure-parameters p) (cadr p))
|
(define (procedure-parameters p) (cadr p))
|
||||||
(define (procedure-body p) (caddr p))
|
(define (procedure-delays p) (caddr p))
|
||||||
(define (procedure-environment p) (cadddr p))
|
(define (procedure-body p) (cadddr p))
|
||||||
|
(define (procedure-environment p) (car (cddddr p)))
|
||||||
|
|
||||||
;; Exercise 4.16: transform the body to scan out internal
|
;; Exercise 4.16: transform the body to scan out internal
|
||||||
;; definitions. Variables will be created unassigned by a let and
|
;; definitions. Variables will be created unassigned by a let and
|
||||||
|
@ -382,13 +404,19 @@
|
||||||
|
|
||||||
(define (make-thunk exp env)
|
(define (make-thunk exp env)
|
||||||
(list 'thunk exp env))
|
(list 'thunk exp env))
|
||||||
|
|
||||||
(define (thunk? obj)
|
(define (thunk? obj)
|
||||||
(tagged-list? obj 'thunk))
|
(tagged-list? obj 'thunk))
|
||||||
|
|
||||||
(define (thunk-exp thunk) (cadr thunk))
|
(define (thunk-exp thunk) (cadr thunk))
|
||||||
(define (thunk-env thunk) (caddr thunk))
|
(define (thunk-env thunk) (caddr thunk))
|
||||||
|
|
||||||
|
;; thunk that should be memoized when forced
|
||||||
|
(define (make-memo-thunk exp env)
|
||||||
|
(list 'memo-thunk exp env))
|
||||||
|
(define (memo-thunk? obj)
|
||||||
|
(tagged-list? obj 'memo-thunk))
|
||||||
|
(define memo-thunk-exp thunk-exp)
|
||||||
|
(define memo-thunk-env thunk-env)
|
||||||
|
|
||||||
;; "thunk" that has been forced and is storing its (memoized) value
|
;; "thunk" that has been forced and is storing its (memoized) value
|
||||||
(define (evaluated-thunk? obj)
|
(define (evaluated-thunk? obj)
|
||||||
(tagged-list? obj 'evaluated-thunk))
|
(tagged-list? obj 'evaluated-thunk))
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
"analyzing-mceval.rkt"
|
"analyzing-mceval.rkt"
|
||||||
"leval.rkt")
|
"leval.rkt")
|
||||||
|
|
||||||
|
(#%provide qualify-arg
|
||||||
|
time-proc)
|
||||||
|
|
||||||
(#%require (only racket current-process-milliseconds))
|
(#%require (only racket current-process-milliseconds))
|
||||||
(#%require (only racket/base module+))
|
(#%require (only racket/base module+))
|
||||||
|
|
||||||
|
@ -31,8 +34,16 @@
|
||||||
(* n (fact (- n 1)))))
|
(* n (fact (- n 1)))))
|
||||||
(fact ,x)))
|
(fact ,x)))
|
||||||
|
|
||||||
(define (fib-program x)
|
|
||||||
`((define (fib n)
|
(define (qualify-arg arg delay)
|
||||||
|
(cond ((eq? delay 'strict) arg)
|
||||||
|
((eq? delay 'lazy) `(,arg lazy))
|
||||||
|
((eq? delay 'lazy-memo) `(,arg lazy-memo))
|
||||||
|
(else (error "Unknown delay" delay))))
|
||||||
|
|
||||||
|
(define (fib-program x delay)
|
||||||
|
`((define (fib
|
||||||
|
,(qualify-arg 'n delay))
|
||||||
(cond ((= n 0) 0)
|
(cond ((= n 0) 0)
|
||||||
((= n 1) 1)
|
((= n 1) 1)
|
||||||
(else
|
(else
|
||||||
|
@ -40,8 +51,9 @@
|
||||||
(fib (- n 1))))))
|
(fib (- n 1))))))
|
||||||
(fib ,x)))
|
(fib ,x)))
|
||||||
|
|
||||||
(define lazy-test-program
|
(define (lazy-test-program delay)
|
||||||
'((define (try a b)
|
`((define (try a
|
||||||
|
,(qualify-arg 'b delay))
|
||||||
(if (= a 0) 1 b))
|
(if (= a 0) 1 b))
|
||||||
(try 0 (/ 1 0))))
|
(try 0 (/ 1 0))))
|
||||||
|
|
||||||
|
@ -56,21 +68,41 @@
|
||||||
(check-equal? (lazy-eval-program (fact-program 5)) 120)
|
(check-equal? (lazy-eval-program (fact-program 5)) 120)
|
||||||
(check-equal? (dd-eval-program (fact-program 10))
|
(check-equal? (dd-eval-program (fact-program 10))
|
||||||
(analyzing-eval-program (fact-program 10)))
|
(analyzing-eval-program (fact-program 10)))
|
||||||
(check-equal? (dd-eval-program (fib-program 5))
|
(check-equal? (dd-eval-program (fib-program 5 'strict))
|
||||||
(analyzing-eval-program (fib-program 5)))
|
(analyzing-eval-program (fib-program 5 'strict)))
|
||||||
(check-equal? (dd-eval-program (fib-program 5))
|
(check-equal? (dd-eval-program (fib-program 5 'strict))
|
||||||
(lazy-eval-program (fib-program 5)))
|
(lazy-eval-program (fib-program 5 'strict)))
|
||||||
(check-equal? (lazy-eval-program lazy-test-program) 1))
|
(check-equal? (lazy-eval-program (fib-program 5 'strict))
|
||||||
|
(lazy-eval-program (fib-program 5 'lazy)))
|
||||||
|
(check-equal? (lazy-eval-program (fib-program 5 'strict))
|
||||||
|
(lazy-eval-program (fib-program 5 'lazy-memo)))
|
||||||
|
(check-equal? (lazy-eval-program (lazy-test-program 'lazy)) 1)
|
||||||
|
(check-equal? (lazy-eval-program (lazy-test-program 'lazy-memo)) 1))
|
||||||
|
|
||||||
(module+ timing
|
(module+ timing
|
||||||
(define dd-fib (time-proc 100 (lambda () (dd-eval-program (fib-program 10)))))
|
(define dd-fib (time-proc 100 (lambda () (dd-eval-program
|
||||||
(define analyzing-fib (time-proc 100 (lambda () (analyzing-eval-program (fib-program 10)))))
|
(fib-program 10 'strict)))))
|
||||||
(define dd-fact (time-proc 100 (lambda () (dd-eval-program (fact-program 50)))))
|
(define analyzing-fib (time-proc 100 (lambda () (analyzing-eval-program
|
||||||
(define analyzing-fact (time-proc 100 (lambda () (analyzing-eval-program (fact-program 50)))))
|
(fib-program 10 'strict)))))
|
||||||
|
(define dd-fact (time-proc 100 (lambda () (dd-eval-program
|
||||||
|
(fact-program 50)))))
|
||||||
|
(define analyzing-fact (time-proc 100 (lambda () (analyzing-eval-program
|
||||||
|
(fact-program 50)))))
|
||||||
|
|
||||||
(display `("Fib: dd " ,dd-fib " analyzing " ,analyzing-fib " speed-up " ,(/ dd-fib analyzing-fib)))
|
(define lazy-fib (time-proc 100 (lambda () (lazy-eval-program
|
||||||
|
(fib-program 10 'lazy)))))
|
||||||
|
(define lazy-memo-fib (time-proc 100 (lambda () (lazy-eval-program
|
||||||
|
(fib-program 10 'lazy-memo)))))
|
||||||
|
|
||||||
|
(display `("Fib: dd " ,dd-fib " analyzing " ,analyzing-fib " speed-up "
|
||||||
|
,(/ dd-fib analyzing-fib)))
|
||||||
(newline)
|
(newline)
|
||||||
(display `("Fact: dd " ,dd-fact " analyzing " ,analyzing-fact " speed-up " ,(/ dd-fib analyzing-fact))))
|
(display `("Fact: dd " ,dd-fact " analyzing " ,analyzing-fact " speed-up "
|
||||||
|
,(/ dd-fib analyzing-fact)))
|
||||||
|
(newline)
|
||||||
|
(display `("Fib: lazy " ,lazy-fib " memoizing " ,lazy-memo-fib " speed-up "
|
||||||
|
,(/ lazy-fib lazy-memo-fib))))
|
||||||
|
|
||||||
|
|
||||||
;; Test results
|
;; Test results
|
||||||
;; test-eval.rkt> (time-proc 100 eval-program fib-program mce-eval mce-user-print)
|
;; test-eval.rkt> (time-proc 100 eval-program fib-program mce-eval mce-user-print)
|
||||||
|
|
Loading…
Reference in New Issue