I just follow the instructions at 3.3.3 of SICP to create the table.
The code I wrote just works well.
here is code_0.scm:
#lang scheme
(require rnrs/base-6)
(require rnrs/mutable-pairs-6)
(define (make-table)
(list '*table*))
(define (assoc key records)
(cond ((null? records)
false)
((equal? key (caar records))
(car records))
(else
(assoc key (cdr records)))))
(define (insert! key value table)
(let ((record (assoc key (cdr table))))
(if record
(set-cdr! record value)
(set-cdr! table
(cons (cons key value)
(cdr table)))))
'OK)
(define (lookup key table)
(let ((record (assoc key (cdr table))))
(if record
(cdr record)
false)))
(define table (make-table))
(insert! 0 0 table)
(insert! 1 1 table)
(insert! 2 2 table)
Further, I want to reference the table as a library in other file, so I write a code_1.scm.
;plus: I delete the "#lang scheme" in code_0 at this time
code_1.scm:
#lang scheme/load
(load "code_0.scm")
(define table-0 (make-table))
(insert! 0 0 table-0)
(insert! 1 1 table-0)
(insert! 2 2 table-0)
compiling error shows:
assoc: not a proper list: {{0 . 0}}
What's wrong with all of this?
Its about LIST in the Scheme, problem of DrRacket, or the version/standard of language?
The problem is that assoc is an existing function in scheme. Try renaming the function to my-assoc, and it will work as expected.
Related
I'm new to scheme and I'm trying to create a function that uses another function to get the price of a list.
I have the list:
(define-struct store(id desc price))
(define master (list
(make-store 1 'milk 2.50)
(make-store 2 'meat 3.29)
(make-store 3 'eggs 1.99)
(make-store 4 'cereal 2.99)
(make-store 5 'bread 2.79)
(make-store 6 'soda 1.29)
(make-store 7 'water 4.99)))
And the funtcion that looks in that list to find elements:
(define (lookup lst id)
(cond ((null? lst) #f)
((= (store-id (car lst)) id)
(list (store-id (car lst))
(store-desc (car lst))
(store-price (car lst))))
(else (lookup (cdr lst) id))))
How would i go about calling this function in another function to get the price to be printed alone? Am i wrong in thinking i can't do so without modifying the lookup function? Can someone walk me through this?
Lookup returns list or #f, so before getting price, you need to check what was returned. Don't modify your code and just add this:
(define (get-only-price id)
(let ((found (lookup master id)))
(if found (third found) #f)))
(get-only-price 3)
(get-only-price 10)
Why go and change the way you return a list when you can just return the object:
(define (lookup lst id)
(cond ((null? lst) #f)
((= (store-id (car lst)) id) (car lst))
(else (lookup (cdr lst) id))))
A store is actual one sales item so I'm guessing the name is slightly off. In a function you can get the price this way:
(define (product-price id)
(let ((item (lookup master id)))
(and item (store-price item))))
In the event the id was not to be found this will also return #f. If you are sure it exists (or want it to fail when it doesn't) you can just do this:
(store-price (lookup master id))
i have been assigned homework to make a general memoization procedure in scheme, so far it works on procedures that take one argument, but fail on what it seems to be the last argument when provided with more than 1. It also fails to memoize procedures that take no arguments.
Any help would be greatly appreciated.
(define mem
(lambda (mem-it func)
(let ((table (make-table) )(func-store func))
(cond
((equal? mem-it 'memoize)
(lambda args
(if (null? args)
func
(let ((prev (lookup args table)))
(or prev
(let ((result (apply func args)))
(insert! args result table)
result))))))
((equal? mem-it 'unmemoize)
(func-store))
(else (display "No Such command"))))))
This is what i have so far
(define (test-proc . args)
(display "computing test-proc of ")
(display args)
(newline)
(if (null? args)
0
(+ (expt (- 42 (car args)) 2)
(apply test-proc (cdr args)))))
And here is the test procedure provided
The error occurs when i try to run the following test
(set! test-proc (mem 'memoize test-proc))
(test-proc 40 41 42 43 44)
Here are the other procedures used
(define (make-table)
(list '*table*))
(define (lookup key table)
(let ((record (assoc key (cdr table))))
(and record (cdr record))))
(define (insert! key value table)
(let ((record (assoc key (cdr table))))
(if record
(set-cdr! record value)
(set-cdr! table
(cons (cons key value) (cdr table))))))
Your memoizarion procedure has a feature where it returns the implementation procedure when no arguments are passed:
((mem 'memoize test-proc)) ; ==> test-proc
The base case of your test procedure will never hit because of this feature thus for (test-proc 1) you can substitute it with the expression (+ 1681 test-proc) which will signal an error since test-proc is not a number.
It's better to use unique magic values:
(define +GET-PROC+ (list "get-proc"))
(test-proc +GET-PROC+) ; ==> original-test-proc
Since we are making a list it's is eq? that data only. In R6RS you can refrain from exporting so that code that uses memoization doesn't really have access to mess with it. All lists that look like it eg ("get-proc") won't be eq? so it can be used as an argument without getting the original procedure.
Since you are not using a standard hash procedure from (rnrs hashtables) or SRFI-69 it's not possible for me to check it but since you are using a list as key your hashtable must use equal? as test. This is often a source of frustration when using hash tables in most lisps.
I am trying to write recursive scheme function that returns the binding (pair) whose name equals the given name. If no such binding is found return the null list. An association list is a list of bindings of names to values: ((name1 val1) ... (namet valuet)).
(define (lookup name assoc_list)
(cond
((null? assoc_list) '())
((equal? name (car (car assoc_list))) car(assoc_list))
(else (lookup name (cdr L)))))
I tested it out with
(define l1 '( (ben "short") (cara "walking") (dan "bald")))
(lookup (car(car l1)) l1)
and it failed
but if i do
(define (look name assoc_list)
(cond
((null? assoc_list) #f)
((equal? name (car (car assoc_list))) #t)
(else (lookup name (cdr L)))))
and run this in scheme
(define l1 '( (ben "short") (cara "walking") (dan "bald")))
(lookup (car(car l1)) l1)
it returns #t
why wont it return the car(assoc_list)
next im going to write a recursive function (lookup-env name environment), which returns the binding with the specified name in an environment (i.e. list of association lists) and null if no such binding is found
An environment can be represented by a list of association lists (i.e. a list of symbol tables), where the first element in the list is nearest scope, the second the next surrounding scope, and the last the outermost scope.
Ah those parentheses ;-) It's (car assoc_list), not car(assoc_list):
(define (lookup name assoc_list)
(cond
((null? assoc_list) '())
((equal? name (car (car assoc_list))) (car assoc_list)) ; <------
(else (lookup name (cdr assoc_list)))))
Note that you can simplify (car (car x)) to (caar x):
(define (lookup name assoc_list)
(cond
((null? assoc_list) '())
((equal? name (caar assoc_list)) (car assoc_list))
(else (lookup name (cdr assoc_list)))))
The procedure you're implementing already exists in some Scheme interpreters, and it's a good idea to reuse existing functionality (don't reinvent the wheel!). Thus the implementation of lookup can be as simple as this:
(define (lookup name assoc_list)
(or (assoc name assoc_list) '()))
The trick, of course, is using assoc (which uses equal? for the comparisons) or a similar procedure, check your interpreter's documentation to discover other search procedures. We need to use or to handle the case where the binding was not found, because by default assoc returns #f in that case, but you need a '(). Let's test it - works as expected:
(define l1 '( (ben "short") (cara "walking") (dan "bald")))
(lookup 'ben l1)
=> '(ben "short")
(lookup 'tom l1)
=> '()
In case you want to implement the procedure from scratch, #uselpa's answer is spot-on: there was a problem with the brackets. Remember, to call a function in Scheme we must do this: (f x), not this: f(x).
I am attempting to write a procedure similar to Scheme's assoc. The only difference between the two, is that I want my procedure only to return the value related to the key given, where as assoc gives the entire pair (key . value). Here is my procedure:
(define alist '((a . 1) (b . 2) (c . 3)))
(define (search-list key list)
(cond ((null? key) #f)
((eq? (caar list) key) (cdar list))
((null? (cdr list)) #f)
(else search-list key (cdr list))))
I seem to be on the right track -- (search-list 'a alist) returns 1. However, when testing with (search-list 'b alist), this is my output: ((b . 2) (c . 3))
I cannot understand why my procedure does not function as I intend it to. I would be very happy if you could point out the error in my procedure. Thanks in advance.
You found your error, but I would suggest other changes:
1) you should check if the list is empty before using caar and the like, because your procedure will fail when called with an empty list.
2) OTOH, there's no need to check if key is null.
3) In Scheme you shouldn't use list as a parameter name in order not to shadow the procedure list.
So I would go for
(define (search-list key lst)
(cond
((null? lst) #f)
((eq? key (caar lst)) (cdar lst))
(else (search-list key (cdr lst)))))
The problem was the call (or the missing call rather) to search-list on the last line. Since this was not wrapped in parentheses, the procedure was never recursively called, and the procedure returned (cdr list) instead of (search-list key (cdr list)). This code works as intended:
(define alist '((a . 1) (b . 2) (c . 3)))
(define (search-list key list)
(cond ((null? key) #f)
((eq? (caar list) key) (cdar list))
((null? (cdr list)) #f)
(else (search-list key (cdr list)))))
Note that you don't want exactly the behavior of assq (which is assoc using eq? not equal?) but you could still use assq in the implementation:
(define (search-list key lst)
(cond ((assq key lst) => cdr)
(else #f)))
> (search-list 'b '((a . 1) (b . 2) (c . 3)))
2
Also, your existing code will have trouble with an a list of '() because caar will fail. Usually in recursive algorithms the base case, which is (null? lst) in your case, is tested first.
I am trying to do some operation in the list if the predicate returns true. But predicate is given as input in command line and it is a function. Let me give an example.
(define (delete-rows table predicate)
do_something)
And the command line looks like this.
(delete-rows student-table
(lambda (table row)
(eq? (get table row 'name) 'ali)))
=> '(students (name id gpa) (ayse 2 3.7))
Thanks for your help in advance.
Here is a very naïve and inefficient implementation in Racket, just to get you on the right track:
(define (list-index e lst)
(- (length lst) (length (memq e lst))))
(define (get table row col)
(list-ref row (list-index col (second table))))
(define (delete-rows table pred)
(list* (first table)
(second table)
(filter (lambda (r) (not (pred table r))) (cddr table))))
then
(define student-table '(students (name id gpa) (ali 1 2) (ayse 2 3.7) (zalde 3 5)))
(delete-rows student-table (lambda (table row) (eq? (get table row 'name) 'ali)))
=> '(students (name id gpa) (ayse 2 3.7) (zalde 3 5))