I need to write a scheme program that finds and replaces a given pattern and I've gotten it to work on only one layer of nesting but when the next car from the list is a list itself, my program doesn't properly recurse in it.
Here is what I have so far:
(define replace
(lambda (source target replacement)
(if (eqv? source target)
replacement
(if (null? source)
'() ;;base case
(if (equal? target (car source))
(cons replacement (replace (cdr source) target replacement))
(cons (car source)
(replace (cdr source) target replacement))
)
)
)
)
)
Use should replace eqv? with equal?. Using eqv? doesn't give the result you'd expect as in the following:
> (eqv? (list 1 2 3) (list 1 2 3))
#f
> (eqv? '(1 2) '(1 2))
#f ; some Schemes may return #t
Regarding your code, it is more readably and compactly written as a series of cond clauses:
(define (replace source target replacement)
(cond ((eqv? source target) replacement)
((null? source) '()) ;;base case
((equal? target (car source))
(cons replacement (replace (cdr source) target replacement)))
((not (list? (car source)))
(cons (car source) (replace (cdr source) target replacement)))
(else
(cons (replace (car source) target replacement)
(replace (cdr source) target replacement)))))
Also, another approach that might more clearly illustrate the algorithm ('handle car and cons it to handing of cdr') is:
(define (replace source target replacement)
(cond ((null? source)'())
((equal? source target) replacement)
(else (let ((next (car source))
(rest (cdr source)))
(cons (if (not (list? next))
next
(replace next target replacement))
(replace rest target replacement)))))
In my initial version I was not checking to see if (car source) was a list and it was thereby being treated as an individual token, to avoid that I added one more condition:
(define replace
(lambda (source target replacement)
(if (eqv? source target)
replacement
(if (null? source)
'() ;;base case
(if (equal? target (car source))
(cons replacement (replace (cdr source) target replacement))
(if (not (list? (car source)))
(cons (car source) (replace (cdr source) target replacement))
(cons (replace (car source) target replacement) (replace (cdr source) target replacement))))))))
Your error is that you don't do replace on the car when it's not a match and it's not an atom. It's possible to write this very compact by allowing to follow all pairs.
(define (replace source target replacement)
(cond ((equal? source target) replacement) ;; equal, return replacement
((not (pair? source)) source) ;; not equal && not pair, return source
(else (cons (replace (car source) target replacement) ;; recurse
(replace (cdr source) target replacement)))))
Related
I'm fairly new to scheme and have been playing around with it and one of the problems I have placed upon myself is to remove all symbols from a single list of elements.
(define lst '(a 2 3 a 2 d 3))
(define removeSymbol
(lambda (lst)
(if (null? lst)
'()
(if (symbol? (car lst))
(removeSymbol (cdr lst))
(cons car lst) (removeSymbol (cdr lst))))))
(removeSymbol lst)
I feel like this should work, but it is not giving me what I am expecting.
My expectation: (list 2 3 2 3)
Any help or guidance would be appreciated.
You mentioned your unmet expectation, but not your result.
I'm guessing you're seeing a syntax error (in Racket, I get: if: bad syntax; has 4 parts after keyword) because the body of your nested if contains 3 s-expressions.
(if (symbol? (car lst))
(removeSymbol (cdr lst))
(cons car lst)
(removeSymbol (cdr lst)))
If you shuffle your parens so that they look like the following, your function should work as expected:
(define lst '(a 2 3 a 2 d 3))
(define (removeSymbol lst)
(if (null? lst)
'()
(if (symbol? (car lst))
(removeSymbol (cdr lst))
(cons (car lst) (removeSymbol (cdr lst))))))
(removeSymbol lst) ;; '(2 3 2 3)
I appreciate you're just working through this example as a learning exercise, but what you're attempting to do could also be achieved (arguably) a bit more idiomatically using the prelude functions filter, negate and symbol?:
(filter (negate symbol?) lst) ;; '(2 3 2 3)
Lets say I have a list containing arguments, how can I display it without the parentheses, example:
(define lst (list 1 2 3)) (display lst)
-> (1 2 3)
But I want it to appear as: 1 2 3
My attempt:
(define (clean-list lst)
(if
(null? lst) (display (null))
(display (car lst)))
(display #\space)
(clean-list (cdr lst)))
It returns the the list without parentheses, but with an error message... Anyone who could help me with this? Also note that im new to racket and racket is my first programming language. Appreciates all answers!
The error is caused by the fact that you always call recursively the function, after the if, even when the list is null.
Here is a correct version:
(define (clean-list lst)
(when (cons? lst)
(display (car lst))
(display #\space)
(clean-list (cdr lst))))
Note that this function prints only the elements on the first level of the list without parentheses, but if an element is a list it is printed with parentheses.
I have a problem with Racket (Scheme) and the procedure "Eval".
To check "eval" in Dr.Racket, we can type in the interpreter, e.g.,
(eval '(+ 5 2))
If we work with lists, we can have,
(eval '(append '(a) '(b)))
That returns,
'(a b)
Until here all is fine,
but I want to do something like:
(define x_list '(append a))
(define y_list '(b c))
(eval (list (car x_list) (cdr x_list) (list (car y_list))))
That obviously doesn't work, because there are not quotes
in front of the lists, i.e. what is doing is,
(eval '(append (a) (b)))
My question is, there is any way to put the quotes in
front of the lists to make this working??
(eval (list (car x_list) (cdr x_list) (list (car y_list))))
Try this:
(eval (list (car x_list) `',(cdr x_list) `',(list (car y_list))))
=> '(a b)
The trick was using quasiquoting, check the documentation for more details.
I'm having trouble understanding how Scheme forms and then detects lists. Hows does it determine the difference between a list and a dotted pair?
A list structure is formed from pairs. A proper list is a chain of pairs where the last pair has the empty list as its cdr.. We can make list? like this:
(define (list? lst)
(cond ((null? lst) #t)
((pair? lst) (list? (cdr lst)))
(else #f)))
Or you could use and/or:
(define (list? lst)
(or (null? lst)
(and (pair? lst)
(list? (cdr lst)))))
I have been working in DrRacket, trying to create a "prefix" function (#lang racket). It should take two lists as an input, and should output #t if pf is either null, or is equal to the beginning of ls.
My problem is that my code doesn't seem to return anything at all when pf is not a prefix of ls and ls isn't null. If I replace the #f in the if statement with something else, like '(), it will return that properly, but if I try to capture the '() and give an output based on that instead, it gives results that don't make sense (like saying that '() isn't null, or that '() doesn't equal '()). It seems to have something to do with having an if statement within a cond statement. Could anyone tell me what it's doing, or why? Is it possible to make this code work correctly, or am I going to need to rework it another way?
Thanks for the help!
(define prefix
(lambda (pf ls)
(cond
[(null? pf) #t]
[(null? ls) #f]
[(if (equal? (car pf) (car ls)) (prefix (cdr pf) (cdr ls)) #f)])
))
Having an if within a cond condition is usually a sign of doing something wrong. I think you meant to say this:
(define prefix
(lambda (pf ls)
(cond
[(null? pf) #t]
[(null? ls) #f]
[(equal? (car pf) (car ls)) (prefix (cdr pf) (cdr ls))]
[else #f])))