Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Memories overcoming me

Name: Anonymous 2021-03-16 4:29

It’s been so many years since I was last here. This message board, the people in it.. It was awful. It’s been nearly 10 years. I missed it. Glad to find my way back here.

Well, have you read your SICP today?

Name: Anonymous 2021-03-16 4:29

or maybe im just a retarded faggot i dunno lol

Name: Anonymous 2021-03-16 6:48

>>1,2
Welcome back to hell, /prog/rider. There's no escape. You, me, and The Sussman, we are all stuck in this void, doomed to be consumed by our own autism.

Name: Anonymous 2021-03-16 7:41

And a ding dong LISP nong to you as well, young lady

Name: Anonymous 2021-03-16 8:17

>>3
Is /prog/ still the same as it’s always been? The normies haven’t found us, right?
I’ll be honest, it’s been 8 years since posting here, I need to come clean. I have still never read even the first chapter of SICP entirely. I’m a disappointment.

Name: Anonymous 2021-03-16 9:49

>>5
There's zero normies here. There's nobody here, it's three autistic people poasting.

Name: Anonymous 2021-03-16 9:50

Exercise 4.5. Scheme allows an additional syntax for cond clauses, (<test> => <recipient>). If <test> evaluates to a true value, then <recipient> is evaluated. Its value must be a procedure of one argument; this procedure is then invoked on the value of the <test>, and the result is returned as the value of the cond expression. For example

(cond ((assoc 'b '((a 1) (b 2))) => cadr)
(else false))

returns 2. Modify the handling of cond so that it supports this extended syntax.

Exercise 4.6. Let expressions are derived expressions, because

(let ((<var1> <exp1>) ... (<varn> <expn>))
<body>)

is equivalent to

((lambda (<var1> ... <varn>)
<body>)
<exp1>

<expn>)

Implement a syntactic transformation let->combination that reduces evaluating let expressions to evaluating combinations of the type shown above, and add the appropriate clause to eval to handle let expressions.

Exercise 4.7. Let* is similar to let, except that the bindings of the let variables are performed sequentially from left to right, and each binding is made in an environment in which all of the preceding bindings are visible. For example

(let* ((x 3)
(y (+ x 2))
(z (+ x y 5)))
(* x z))

returns 39. Explain how a let* expression can be rewritten as a set of nested let expressions, and write a procedure let*->nested-lets that performs this transformation. If we have already implemented let (exercise 4.6) and we want to extend the evaluator to handle let*, is it sufficient to add a clause to eval whose action is

(eval (let*->nested-lets exp) env)

or must we explicitly expand let* in terms of non-derived expressions?

Exercise 4.8. ``Named let'' is a variant of let that has the form

(let <var> <bindings> <body>)

The <bindings> and <body> are just as in ordinary let, except that <var> is bound within <body> to a procedure whose body is <body> and whose parameters are the variables in the <bindings>. Thus, one can repeatedly execute the <body> by invoking the procedure named <var>. For example, the iterative Fibonacci procedure (section 1.2.2) can be rewritten using named let as follows:

(define (fib n)
(let fib-iter ((a 1)
(b 0)
(count n))
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1)))))

Modify let->combination of exercise 4.6 to also support named let.

Exercise 4.9. Many languages support a variety of iteration constructs, such as do, for, while, and until. In Scheme, iterative processes can be expressed in terms of ordinary procedure calls, so special iteration constructs provide no essential gain in computational power. On the other hand, such constructs are often convenient. Design some iteration constructs, give examples of their use, and show how to implement them as derived expressions.

Exercise 4.10. By using data abstraction, we were able to write an eval procedure that is independent of the particular syntax of the language to be evaluated. To illustrate this, design and implement a new syntax for Scheme by modifying the procedures in this section, without changing eval or apply.

4.1.3 Evaluator Data Structures

In addition to defining the external syntax of expressions, the evaluator implementation must also define the data structures that the evaluator manipulates internally, as part of the execution of a program, such as the representation of procedures and environments and the representation of true and false.

Testing of predicates

For conditionals, we accept anything to be true that is not the explicit false object.

(define (true? x)
(not (eq? x false)))
(define (false? x)
(eq? x false))

Representing procedures

To handle primitives, we assume that we have available the following procedures:

(apply-primitive-procedure <proc> <args>)
applies the given primitive procedure to the argument values in the list <args> and returns the result of the application.

(primitive-procedure? <proc>)
tests whether <proc> is a primitive procedure.

These mechanisms for handling primitives are further described in section 4.1.4.

Compound procedures are constructed from parameters, procedure bodies, and environments using the constructor make-procedure:

(define (make-procedure parameters body env)
(list 'procedure parameters body env))
(define (compound-procedure? p)
(tagged-list? p 'procedure))
(define (procedure-parameters p) (cadr p))
(define (procedure-body p) (caddr p))
(define (procedure-environment p) (cadddr p))

Operations on Environments

The evaluator needs operations for manipulating environments. As explained in section 3.2, an environment is a sequence of frames, where each frame is a table of bindings that associate variables with their corresponding values. We use the following operations for manipulating environments:

(lookup-variable-value <var> <env>)
returns the value that is bound to the symbol <var> in the environment <env>, or signals an error if the variable is unbound.

(extend-environment <variables> <values> <base-env>)
returns a new environment, consisting of a new frame in which the symbols in the list <variables> are bound to the corresponding elements in the list <values>, where the enclosing environment is the environment <base-env>.

(define-variable! <var> <value> <env>)
adds to the first frame in the environment <env> a new binding that associates the variable <var> with the value <value>.

(set-variable-value! <var> <value> <env>)
changes the binding of the variable <var> in the environment <env> so that the variable is now bound to the value <value>, or signals an error if the variable is unbound.

To implement these operations we represent an environment as a list of frames. The enclosing environment of an environment is the cdr of the list. The empty environment is simply the empty list.

(define (enclosing-environment env) (cdr env))
(define (first-frame env) (car env))
(define the-empty-environment '())

Each frame of an environment is represented as a pair of lists: a list of the variables bound in that frame and a list of the associated values.14

(define (make-frame variables values)
(cons variables values))
(define (frame-variables frame) (car frame))
(define (frame-values frame) (cdr frame))
(define (add-binding-to-frame! var val frame)
(set-car! frame (cons var (car frame)))
(set-cdr! frame (cons val (cdr frame))))

To extend an environment by a new frame that associates variables with values, we make a frame consisting of the list of variables and the list of values, and we adjoin this to the environment. We signal an error if the number of variables does not match the number of values.

(define (extend-environment vars vals base-env)
(if (= (length vars) (length vals))
(cons (make-frame vars vals) base-env)
(if (< (length vars) (length vals))
(error "Too many arguments supplied" vars vals)
(error "Too few arguments supplied" vars vals))))

To look up a variable in an environment, we scan the list of variables in the first frame. If we find the desired variable, we return the corresponding element in the list of values. If we do not find the variable in the current frame, we search the enclosing environment, and so on. If we reach the empty environment, we signal an ``unbound variable'' error.

(define (lookup-variable-value var env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars)
(env-loop (enclosing-environment env)))
((eq? var (car vars))
(car vals))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame)))))
(env-loop env))

To set a variable to a new value in a specified environment, we scan for the variable, just as in lookup-variable-value, and change the corresponding value when we find it.

(define (set-variable-value! var val env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars)
(env-loop (enclosing-environment env)))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable -- SET!" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame)))))
(env-loop env))

To define a variable, we search the first frame for a binding for the variable, and change the binding if it exists (just as in set-variable-value!). If no such binding exists, we adjoin one to the first frame.

(define (define-variable! var val env)
(let ((frame (first-frame env)))
(define (scan vars vals)
(cond ((null? vars)
(add-binding-to-frame! var val frame))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(scan (frame-variables frame)
(frame-values frame))))

The method described here is only one of many plausible ways to represent environments. Since we used data abstraction to isolate the rest of the evaluator from the detailed choice of representation, we could change the environment representation if we wanted to. (See exercise 4.11.) In a production-quality Lisp system, the speed of the evaluator's environment operations -- especially that of variable lookup -- has a major impact on the performance of the system. The representation described here, although conceptually simple, is not efficient and would not ordinarily be used in a production system.15

Exercise 4.11. Instead of representing a frame as a pair of lists, we can represent a frame as a list of bindings, where each binding is a name-value pair. Rewrite the environment operations to use this alternative representation.

Exercise 4.12. The procedures set-variable-value!, define-variable!, and lookup-variable-value can be expressed in terms of more abstract procedures for traversing the environment structure. Define abstractions that capture the common patterns and redefine the three procedures in terms of these abstractions.

Exercise 4.13. Scheme allows us to create new bindings for variables by means of define, but provides no way to get rid of bindings. Implement for the evaluator a special form make-unbound! that removes the binding of a given symbol from the environment in which the make-unbound! expression is evaluated. This problem is not completely specified. For example, should we remove only the binding in the first frame of the environment? Complete the specification and justify any choices you make.

Name: Anonymous 2021-03-16 9:51

FrozenVoid and Nikita the Russian are the only people poasting code here, which is very depressing.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List