I am stuck with this particular problem I was doing for fun:
Why does it cause a contract violation everytime car comes around? And are there any possible fixes?
(define (fv expr)
(cond ((eq? (car expr) 'lambda) (fv (cadr (cdr expr))))
((pair? (car expr)) (union (fv (car expr)) (fv (cdr expr))))
((symbol? (car expr)) (remove (car expr) (fv (cdr expr))))
(else '())))
(define (union set1 set2)
(cond ((null? set1) set2)
((member (car set1) set2) (union (cdr set1) set2))
(else (cons (car set1) (union (cdr set1) set2)))))
(define (remove item set)
(cond ((null? set) '())
((equal? item (car set)) (cdr set))
(else (cons (car set) (remove item (cdr set))))))
Input = (fv '(λ f (λ x (f ((t g) g)))))
Output =
car: contract violation expected: pair? given: '()
Output Should Be: (t g)
The error message:
car: contract violation expected: pair? given: '()
means that the function car was called with the argument '() (the empty list) and this gives an error.
Now you know that the problem is related to a call to car.
Since car is called multiple times in your program it is hard
to spot which car is the culprit. Presumably your Scheme implementation
displays a source locations that points to the offending expression.
But let's say you are not so lucky. In that case, you'll need to figure out which function has the problem. Inserting a few calls to display helps:
(define (fv expr)
(display (list 'fv: 'expr expr) (newline)
(cond ((eq? (car expr) 'lambda) (fv (cadr (cdr expr))))
((pair? (car expr)) (union (fv (car expr)) (fv (cdr expr))))
((symbol? (car expr)) (remove (car expr) (fv (cdr expr))))
(else '())))
(define (union set1 set2)
(display (list 'union: 'set1 set1 'set2 set2) (newline)
(cond ((null? set1) set2)
((member (car set1) set2) (union (cdr set1) set2))
(else (cons (car set1) (union (cdr set1) set2)))))
(define (remove item set)
(display (list 'remove: 'item item 'set set) (newline)
(cond ((null? set) '())
((equal? item (car set)) (cdr set))
(else (cons (car set) (remove item (cdr set))))))
If you try your example now, you'll see which function is called before the error occurs. In this case, I bet the problem is fv. Here car is called without a check that the argument is a non-empty list first.
Related
I have the following code:
(defun rember
(lambda (a lat)
(cond
((null lat) '())
(else (cond
((eq (car lat) a) (cdr lat))
(else (rember a
(cdr lat))))))))
(rember 2 '(4 5 6 7))
When I run this using C-x C-e, I get the following error:
Invalid function: (lambda (lambda (a lat) (cond ((null lat) (quote nil)) (else (cond\
((eq (car lat) a) (cdr lat)) (else (rember a (cdr lat))))))) nil)
I don't know why. Can someone help?
Looks like you're mixing up Lisp and Scheme syntax for defining functions. In Lisp, as you're using defun instead of defvar, it is already implied that you're defining a function, so you don't need to wrap the code in lambda:
(defun rember (a lat)
(cond
((null lat) '())
(else (cond
((eq (car lat) a) (cdr lat))
(else (rember a
(cdr lat)))))))
(Next you'll find that else is not treated specially inside cond in Emacs Lisp, so you'll need to use t instead.)
(define (element-of-set x lst1)
(cond ((null? lst1) '())
((equal? x (car lst1)) (cons (car lst1) (element-of-set x (cdr lst1))))
(else
(element-of-set x (cdr lst1)))))
(define (helper set1 set2) (append set1 set2))
(define (union-set set1 set2)
(cond ((null? set1) '())
((> (length (element-of-set (car set1) (helper set1 set2))) 1) (cons (car set1) (union-set (cdr set1) (cdr set2))))
((> (length (element-of-set (car set2) (helper set1 set2))) 1) (cons (car set2) (union-set (cdr set1) (cdr set2))))
(else
(append (helper set1 set2) (union-set (cdr set1) (cdr set2))))))
This code is suppose to find the union of 2 sets. I tried to put the two sets together and then take out any repeats but it didn't work.
How about this:
#lang racket
(require racket/set)
(define (union-set set1 set2)
(set-union set1 set2))
(union-set '(1 2 3) '(4 3 2))
=> '(4 1 2 3)
FYI, set is a built-in data type in Racket, so it's easy to write a set union - just call the existing procedure! Anyway, if you want to roll your own version it's also easy, and simpler than your current implementation:
(define (element-of-set x lst1)
(cond ((null? lst1) #f)
((equal? x (car lst1)) #t)
(else (element-of-set x (cdr lst1)))))
(define (union-set set1 set2)
(cond ((null? set1) set2)
((element-of-set (car set1) set2)
(union-set (cdr set1) set2))
(else
(cons (car set1) (union-set (cdr set1) set2)))))
Here's how I'd do it in Common Lisp if it didn't include functions for set operations.
(defun set-union (set1 set2)
(remove-duplicates (append set1 set2)))
I'll write one in Scheme.
Using a Scheme-like language, I am converting
(quote (lambda (a b) (* a b) (+ a b))))
to:
(quote (lambda (a) (lambda (b) (+ a b) (* a b))))
but with my current implementation I am getting an extra pair of parenthesis around the expressions (+ a b) and (* a b):
(lambda (a) (lambda (b) ((+ a b) (* a b))))
I have spent a lot of time trying to fix this problem, but can't figure it out. I feel like the fix should be trivial.
Here is my code currently:
(define (conv lyst)
(define (helper args)
(cond
((null? args) (append (cddr lyst) args))
(else (cons (car lyst)
(cons (list (car args))
(list (helper (cdr args))))))))
(cond
((eq? 1 (length (car (cdr lyst)))) lyst)
(else (helper (car (cdr lyst))))))
I think your implementation can be simplified. This should work:
(define (conv lyst)
(define (helper args)
(if (null? (cdr args))
(cons 'lambda
(append (list (list (car args)))
(cddr lyst)))
(list 'lambda
(list (car args))
(helper (cdr args)))))
(helper (cadr lyst)))
Or even simpler, using quasiquoting and splicing:
(define (conv lyst)
(define (helper args)
(if (null? (cdr args))
`(lambda (,(car args)) ,#(cddr lyst))
`(lambda (,(car args)) ,(helper (cdr args)))))
(helper (cadr lyst)))
Either way, it works as expected:
(conv '(lambda (a b) (* a b) (+ a b)))
=> '(lambda (a) (lambda (b) (* a b) (+ a b)))
I can get the odd elements of a list using the following code:
(define (odds lis)
(cond
((null? lis) '())
((not (list? lis)) (quote (Usage: odds(list))))
((null? (car lis)) '())
((= (length lis) 1) (car lis))
(else (cons (car lis) (odds (cddr lis))))))
but when input list of odd length
For example: (odds '(a b c d e))
It will return
(a c . e)
How can i get rid of this obnoxious period?
Try this, it's a change in only one line:
(define (odds lis)
(cond
((null? lis) '())
((not (list? lis)) (quote (Usage: odds(list))))
((null? (car lis)) '())
((= (length lis) 1) lis) ; change here
(else (cons (car lis) (odds (cddr lis))))))
In the highlighted line, you were returning a single element instead of a proper list (a null-terminated list), that's what was causing the problem.
I have been working on the following function flatten and so far have it working for just lists. I was wondering if someone could provide me with some insight on how to get it work with pairs? For example (flatten '(a .a)) would return (a a). Thanks.
(define (flatten list)
(cond ((null? list) null)
((list? (car list)) (append (flatten (car list)) (flatten (cdr list))))
(else
(cons (car list) (flatten (cdr list))))))
Here's one option:
(define (flatten x)
(cond ((null? x) '())
((pair? x) (append (flatten (car x)) (flatten (cdr x))))
(else (list x))))
This does what you want, without requiring append, making it o(n). I walks the list as a tree. Some schemes might throw a stack overflow error if the list is too deeply nested. In guile this is not the case.
I claim no copyright for this code.
(define (flatten lst)
(let loop ((lst lst) (acc '()))
(cond
((null? lst) acc)
((pair? lst) (loop (car lst) (loop (cdr lst) acc)))
(else (cons lst acc)))))
(define (flatten l)
(cond
[(empty? l) empty]
[(list? l)
(append (flatten (first l))
(flatten (rest l)))]
[else (list l)]))