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).
Related
I'm new to Scheme and to functional programming so please be gentle.
I'm trying to implement a function that takes a list and a pivot and return a list that contains the following 2 lists:
One for all elements that are less or equal to the pivot,
and one for all the elements that are greater than the pivot.
So I wrote the following code (EDITED (& WORKING) CODE - PROBLEM SOLVED):
define helper (lambda (lst pivot)
(define lst1 null)
(define lst2 null)
(define my-split (lambda (lst pivot lst1 lst2)
(if (null? lst)
(list lst1 lst2)
(if (<= (car lst) pivot)
(my-split (cdr lst) pivot (cons (car lst) lst1) lst2)
(my-split (cdr lst) pivot lst1 (cons (car lst) lst2))))))
(my-split lst pivot lst1 lst2)))
My current problem is that lst1 and lst2 are null at the end of the run so I guess the problem is with the lines (cons (car lst) lst1) & (cons (car lst) lst2))).
I saw some implementations on the web which use some complex commands that I'm not allowed to use (yes, it's homework).
Please offer ways to fix my code rather than offering your own.
Thanks
You correctly identified the two lines that are the main problem. cons just builds and returns a new list, whereas you're trying to mutate the variables lst1 and lst2. The correct way to do this is (set! lst1 (cons (car lst) lst1)) and (set! lst2 (cons (car lst) lst2)). Keep in mind, though, that good functional programming style avoids mutation. A good way to do that in this case would be to pass the two sub-lists as arguments as you recur down the main list, then return them when you get to the end.
Just like an expression like str.concat("hey") in Java doesn't change what str is (cons 1 lst1) doesn't change what lst1 is. It just returns a new value. Most of your function consist of dead code and if you really want to learn functional programming then altering bindings and objects are off limits.
You need to do something like this:
(define (count-odds lst)
(define (helper lst odds)
(cond ((null? lst)
odds)
((odd? (car lst))
(helper (cdr lst) (+ 1 odds)))
(else
(helper (cdr lst) odds))))
(helper lst 0))
(count-odds '(1 2 3))
; ==> 2
We never alter odds, we just update what is sent to the next recursion. Since Scheme has tail call elimination this is just like updating the variable in a while loop without actual mutation.
I am trying to check the first atom in a list against the other atoms in a list, so if the first atom is 3 and the 3rd atom is three, I would want to evaluate it to false.
I have something like
(define (doubles a_list)
(cond
((null? a_list) #t)
(not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))
I have a feeling that this will only check atoms next to each other and not the one atom with the rest of them. what can i do to check all the items with the first one?
You want to repeatedly compare the first two elements of your list, reducing the cdr as you go:
(define (unique-first? x)
; uncomment the following line to trace the execution
;(display x) (newline)
(or (null? x) (null? (cdr x))
(and (not (eq? (car x) (cadr x)))
(unique-first? (cons (car x) (cddr x))))))
note on special cases:
(unique-first? '()) -> #t
(unique-first? '(a)) -> #t
(which, indeed, verify the "first element doesn't appear twice" criteria).
I've got my tea, my code-review hat and a few spare minutes. You know what time it is.
What you want is a predicate that will tell you if there are duplicates of the first atom in a list.
(define (doubles a_list)
(cond ((null? a_list) #t)
(not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))
Regardless of anything else, this won't work because it has unbalanced parentheses.
(define (doubles a_list)
(cond ((null? a_list) #t)
(not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))))
That revised version won't work because it has a malformed second clause in the case. Oddly, it does seem to evaluate fine, but when you call it, you'll get an odd error message
Welcome to Racket v5.3.6.
> (define (doubles a_list)
(cond ((null? a_list) #t)
(not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))))
> (doubles (list 1 2 3 4 5 6 7 3))
application: not a procedure;
expected a procedure that can be applied to arguments
given: #f
arguments...: [none]
>
The direct cause is this bit
... ((eq? (car a_list) (car (cdr a_list)))) ...
Because of the extra parens surrounding this expression, what it actually means is
"See if the first element of a_list is the same as the second, then call the result of that check as a function".
This is not what you want. The correct resolution is getting that not into these parens, which would make that a valid cond clause.
(define (doubles a_list)
(cond ((null? a_list) #t)
((not (eq? (car a_list) (car (cdr a_list))))
(doubles (cdr a_list)))))
You can't call car on the empty list in Scheme. This works fine, for some definition of "fine", in Common Lisp but will throw you an error here.
> (define (doubles a_list)
(cond ((null? a_list) #t)
((not (eq? (car a_list) (car (cdr a_list))))
(doubles (cdr a_list)))))
> (doubles (list 1 2 3 4 5 6 7 3))
car: contract violation
expected: pair?
given: '()
>
The cause of this error is that you're checking whether a_list is null?, but then calling (car (cdr a_list)) later on. You'll get this error in the situation where a_list is something like (3). The fix for this is checking whether a_list or its cdr are null?
(define (doubles a_list)
(cond ((or (null? a_list) (null? (cdr a_list))) #t)
((not (eq? (car a_list) (car (cdr a_list))))
(doubles (cdr a_list)))))
> (doubles (list 1 2 3 4 5 6 7 3))
#t
Now that we've got a version of your function that doesn't error out, lets take a look at your logic. The procedure for finding doubles in a list is
for lists of length zero or one, the answer is False, since there can be no doubles in a list shorter than two elements
otherwise, check if the first element of the list is in the rest.
if it is, the answer is True since we've found a duplicate
Now, you've named your function doubles, but your prose explanation tells me that it really should have been unique-first?. Because you're not looking for doubles, your're looking to check if the first element of your list is unique among its peers. What you really want to do is
for lists of length one, the answer is True, since that single element must be unique (I'm going to assume that you want the same for lists of length zero, but that might not actually make sense depending on the application)
otherwise, check that the first element of the list is not in the rest.
That translates to
(define (unique-first? a_list)
(if (or (null? a_list) (null? (cdr a_list)))
#t
(not (member? (car a_list) (cdr a_list)))))
The member? function is fairly straightforward, and works on the same principles.
(define (member? elem lst)
(cond ((null? lst) #f)
((eq? elem (car lst)) #t)
(else (member? elem (cdr lst)))))
Finally, a couple of style points. The Scheme convention is to name predicates with a trailing ?, which will hint to your functions' callers that it will return #t or #f (I've done this above), and to use spinal-case rather than snake_case for names.
(define (unique-first? a-list)
(if (or (null? a-list) (null? (cdr a-list)))
#t
(not (member? (car a-list) (cdr a-list)))))
In Scheme or Racket is it possible to detect the caller of a function?
For example, I can write a function to test if a list is a list of atoms as follows:
(define atom? (lambda (x) (and (not (pair? x)) (not (empty? x)))))
(define lat? (lambda (l)
(define latt?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (latt? (cdr l)))
(else #f))))
(if (null? l) #f (latt? l))))
but instead of the above, is there a function like "called-by" to do something like this:
(define lat?
(lambda (l)
(cond
((and (null? l) (called-by "lat?")) #t)
((atom? (car l)) (lat? (cdr l)))
(else #f))))
The usual way to do this is to add some argument to the function, or make a loop via an internal definition as you did. Other than that, there is no reliable way to find out the caller of a function.
But in your case, it seems like a good lack of feature -- using it for the above problem is pretty bad. There's nothing wrong with the internal helper version. (It's also quite similar to any other language.)
Finally, I'd expect (lat? null) to return #t since it is a list that has only atoms as elements.
I've got a program I'm writing for a class to substitute the left-most occurrence of a variable with a new variable. (It actually allows you to provide an equivalence relation yourself, as well). The thing is, in Chez Scheme 8.2, this substitutes the right-most occurrence, if the left most is inside a list. We use a server running some version of scheme (I'm not sure which version), and on the server it substitutes, correctly, the left-most occurrence. Below is the code:
(define subst-leftmost
(lambda (new old ls proc)
(let ([keep-going? #t])
(letrec ([helper
(lambda (ls)
(cond [(null? ls) ls]
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
[(and keep-going? (proc old (car ls)))
(set! keep-going? #f) (cons new (cdr ls))]
[else (cons (car ls) (helper (cdr ls)))]))]) (helper ls))))
This is called like so: (subst-leftmost 'x 'a '(d b c (a) b a) eq?) which should produce the output (d b c (x) b a), and does on the server. In Chez scheme, however, it produces (d b c (a) b x). I think the difference is due to the line
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
evaluating the helper of the car and the helper of the cdr in a not-set order.
My question is this: Which version of scheme is following the standard, and how can I modify my code so that it works correctly in both versions?
(I've already talked to my professor about this. He's going to address the class about it on Monday, once he can think about it some, but I'm curious. I also already got the full points for the assignment, so don't worry about the ethics of helping me, in that regard.)
There isn't any, sorry. Here's the relevant legalese. Use LETs or LET* if you need to evaluate sub-expressions in a particular order.
Scheme guarantees no specific order (as Cirno has said). If your code has no side-effects, this doesn't matter.
However, your code is side-effecting (because of the set! to an outside variable), so, you have some choices:
Use Racket (which is committed to using left-to-right order, last time I talked to a Racket dev)
Structure your code to remove side-effects, so that your helper function doesn't change any variable or state outside it
Use appropriate lets to ensure the ordering you need (as Cirno suggested); in particular, change (cons (helper (car ls)) (helper (cdr ls))) to:
(let ((depth-first (helper (car ls))))
(cons depth-first (helper (cdr ls))))
I am doing a scheme program which takes in a list and then reverse it. So far it works for simple list, which does not contain any sublist, but when I test it for a list contains sublist, it fails. Please help me where is wrong with it.
Here is the code:
(define deep-reverse
(lambda (L)
(cond
((empty? L) '())
(else (append (deep-reverse (rest L)) (list (first L)))))))
(define (deeprev L)
(if (null? L) '()
(if (list? (car L))
(if (chek (car L)) (append (deeprev (cdr L)) (list (reverse (car L))))
(append (deeprev (cdr L)) (list (deeprev (car L)))))
(append (deeprev (cdr L)) (list (car L))))))
First of all, you are using undefined Scheme functions. I am going to work off the following assumptions:
empty? is null?
rest is cdr
first is car
Your code works by taking the first element in a list and adding it to another list. However, that first element of a list can be a list itself. You need to test to see if the element that you're working on is atomic or a list. If it's a list, then you call deep-reverse recursively.
If you would like to see code appended to this, leave a comment.