SICP 5.2 Assembler - scheme

I've been reading through chapter 5 of sicp and have gotten stuck on a piece of code--namely, the assembler presented in 5.2. This is what it looks like:
(define (extract-labels text receive)
(if (null? text)
(receive '() '())
(extract-labels (cdr text)
(lambda (insts labels)
(let ((next-inst (car text)))
(if (symbol? next-inst)
(receive insts
(cons (make-label-entry next-inst insts)
labels))
(receive (cons (make-instruction next-inst) insts)
lables)))))))
Isn't the lambda only going to be called when the text is null? So how can we ask for the car of 'text' then?
EDIT
Thanks for the answers, but I'm still not seeing it. If the text is not null, doesn't extract-lables call itself recursively, until the text is null? In which case how can we call the car of it?

The lambda gets the appropriate scope: at the time the lambda is defined text is not null, so calling car text works fine.

if takes up to three arguments: a condition, a if-true (then) expression, and an if-false (else) expression. The indentation is all weird, so it looks wrong.
It should appear as
(define (extract-labels text receive)
(if (null? text)
(receive '() '())
(extract-labels (cdr text)
(lambda (insts labels)
(let ((next-inst (car text)))
(if (symbol? next-inst)
(receive insts
(cons (make-label-entry next-inst insts)
labels))
(receive (cons (make-instruction next-inst) insts)
labels)))))))
Observe that the result of the expression is (receive '() '()) if text is null and (extract-labels ...) otherwise.

Related

Racket function passing empty list instead of actual list

I'm pretty new to racket and I'm trying to make a finite state machine for a project. here's what I have so far.
#lang racket
(define (test rules cs pass lst)
(if (eq? (length lst) 0)
(if (member cs pass)
(write 'passed)
(write 'failed))
(test rules (next rules cs (car lst)) (cdr lst))))
(define (next rules cs input)
(if (eq? cs (car (car rules)))
(if (eq? input (car(cdr(car rules))))
(car(cdr(cdr(car rules))))
((next (cdr rules) cs input)))
(next (cdr rules) cs input)))
then I input
(define rules '('(0 a 0) '(0 b 1) '(1 a 0) '(1 b 1)))
(define pass '(1))
(test rules 0 pass '(a b a b))
and for a reason that I cannot figure out, I get
this error on the next function. It acts as though rules is an empty list, which I'm pretty sure it's not. Anyway if anyone could tell me why it's doing that it would really help.
Thanks!
EDIT1
Thanks so much for the help guys. It's really helping. The code is working entirely until the end, but now it throws an error at the end of my code if I test multiple lists with testmany.
(define (testmany rules cs pass lst)(if (eq? (length lst) 0)
(write 'done)
((test rules cs pass (car lst))
(testmany rules cs pass (cdr lst)))))
(define (test rules cs pass lst) (if (eq? (length lst) 0)
(if (member cs pass)
(write 'accepted.....)
(write 'rejected.....))
(test rules (next rules cs (car lst)) pass (cdr lst))))
(define (next rules cs input) (if (eq? cs (car (car rules)))
(if (eq? input (car(cdr(car rules))))
(car(cdr(cdr(car rules))))
(next (cdr rules) cs input))
(next (cdr rules) cs input)))
The code doesn't seem to know when to stop the recursion of the testmany function. When the list is empty, it prints done, but then continues the next part as if the list still had elements, throwing this error. If anyone knows why it is throwing this error please let me know.
Thanks!
You forgot the begin:
(define (testmany rules cs pass lst) (if (eq? (length lst) 0)
(write 'done)
(begin
; ^^^^^ here
(test rules cs pass (car lst))
(testmany rules cs pass (cdr lst)))))
Without it, the return value of (test rules cs pass (car lst)) is attempted to be used as a function; but it is #<void>, the result of (write ....) form, which is the last one evaluated (more like, executed) by your test function.
By the way, #<void> is not an empty list; it's more like a non-value.
edit: the reason it does recurse to the end (without the begin) is that to apply a function foo in (foo val) to a value val, both expressions are evaluated first.
It is only after the evaluation of val, i.e. (testmany ...), finishes fully that the error is discovered that the value of foo, i.e. (test ...) expression, is not in fact a function, and can not be applied.

Scheme Function Maker

I've been working on this procedure in Scheme (specifically Pretty Big) and I've hit a brick wall. What I'm trying to do is create a procedure that can create other procedures or functions. For the most part I think I'm on the correct track.
(define (function-maker function-specs)
(let* [(specs (map cdr function-specs))
(name (caar specs))
(args (cadr function-specs))
(body (cdr(cdr function-specs)))]
(eval(list 'define name
(list 'lambda args body)))))
Current Output:
Above is the current output and I'll explain to the best of my knowledge what is happening. The input takes in three arguments essentially. A name, to name the function. Arguments for the function and finally the body of the function.
The three arguments are then listed together and then it's supposed to create a new function. The picture above shows the error that I'm reaching. Thanks for the help!
To see what's happening, get rid of the eval and examine the list:
(define (function-maker function-specs)
(let* [(specs (map cdr function-specs))
(name (caar specs))
(args (cadr function-specs))
(body (cdr(cdr function-specs)))]
(list 'define name
(list 'lambda args body))))
> (function-maker '((name: add5) (x) (+ x 5)))
'(define add5 (lambda (x) ((+ x 5))))
As you can see, there are too many parentheses in the body, so you're attempting to use the resulting number as a procedure.
You want
(body (car (cdr (cdr function-specs))))
or
(body (caddr function-specs))

Null use in a small Scheme script

I'm just learning how to write in Scheme and hitting a road block with the use of Null. I have the script below from this video series...
https://www.youtube.com/watch?v=Qqext1NwmqM&index=2&list=PLgyU3jNA6VjRMB-LXXR9ZWcU3-GCzJPm0
Script...
(define (my-map fn lst)
(if (null? lst)
null
(cons (fn (car lst)) (my-map fn (cdr lst)))))
This is just redefining the map function in Scheme. It fails at the third line as "null: undefined. cannot reference undefined identifier" when I pass a function and a list.
I just copied what the video shows so not sure why it's failing. If I switch out null for '(), that works. Anyone know why?
It's quite possible that your Scheme interpreter doesn't have the null symbol bound to the '() value, as this is not required by the language specification. Either do this:
(define null '())
Or equivalently this, as you already guessed:
(define (my-map fn lst)
(if (null? lst)
'()
(cons (fn (car lst))
(my-map fn (cdr lst)))))
Notice that the latest Scheme report states that (null? obj) should return #t
if obj is the empty list, otherwise returns #f
So it's ok to define null as '().

application: not a procedure

I'm in the process of learning Scheme. During an exercise (trying to find a specific value in a registry). When running this bit of code, I get the error message:
application: not a procedure;
expected a procedure that can be applied to arguments
given: (342 "Bike" piece 250)
arguments...: [none]
The code in question:
(define get-post
(lambda (post varunr)
(define find-post
(lambda (post)
(cond (null? post) (display "Errormessage-For-User")
(member varunr (car (car post)))(car post)
(else (find-post (cdr post))))))
find-post (post))) ;; <--- Here's the error message
Thanks for any help you can provide.
Try this:
(define get-post
(lambda (post varunr)
(define find-post
(lambda (post)
(cond ((null? post) (display "Errormessage-For-User"))
((member varunr (car (car post))) (car post))
(else (find-post (cdr post))))))
(find-post post)))
Remember: in Scheme functions are called like this: (f x), not like this: f(x). And in a cond expression, each pair of condition/expression must be surrounded by (). You have to be careful where you put those parentheses, use your IDE's syntax highlighting and formatting capabilities to avoid errors like these.

Scheme error: "Syntactic keyword may not be used as an expression: if"

I'm new to scheme and I'm trying to do a small very straight forward program.
But I keep getting this error message "Syntactic keyword may not be used as an expression: if".
Can anyone tell me if I'm missing something in my program or if I'm doing some sort of mistake?
Here is my program.
(define (foo lis k)
(COND
((NULL? lis) '())
(IF (< (CAR lis) k)
(display (CAR lis))
ELSE (display (CDR lis)))
))
(foo '(1 5 3 2 4) 3)
Thanks
-Gunnlaugur
I'm not sure what you are trying to do, but it seems like if is not needed there:
(define (foo lis k)
(cond
((null? lis) '())
((< (car lis) k)
(display (car lis)))
(else (display (cdr lis)))))
(foo '(1 5 3 2 4) 3)
cond takes expressions in the form*
(condition expr1 expr2 ... result)
Since you gave
(if (< (car lis) k) (display (car lis)) else (display (cdr lis)))
Scheme will try to see if if is true, and then run the next four expressions (< (car lis) k), (display (car lis)), else, and (display (cdr lis)). It runs into a couple problems, though. if cannot be evaluated as true or false, since it is syntax. Even if it could be, you would get a misplaced aux keyword else error. And if that didn't happen, it would do both (display (car lis)) and (display (cdr lis)) (which is not what you want.
I'm guessing that you don't actually want to use display. If you're running this interactively in a terminal, Scheme will evaluate the result of your function and print it for you.
* a slight simplification. Look in TSPL4 for details.

Resources