I am trying to create a procedure in scheme which replaces a certain element in a list with another element
(define (replace var player list)
(if (null? list)
'()
(if (list? (car list))
(cons (replace var player (car list))
(replace var player (cdr list))
(if (equal? var (car list))
(cons player (replace var player (cdr list)))
(cons (car list) (replace var player (cdr list)))
))))
Currently the procedure does not replace any elements.
This is the input list
'(q w (e r (t x)) y u i (o (x)) p x a s d)
I would like to replace the 'x' elements in that list with 'y'.
This is the desired output
'(q w (e r (t y)) y u i (o (y)) p y a s d)
We have tried
(replace_by 'x 'y '(q w (e r (t x)) y u i (o (x)) p x a s d)
but it does not seem to be working
The posted code is missing one parenth at the end, and has a misplaced parenth. The first cons expression needs to be closed by a parenth:
(define (replace var player list)
(if (null? list)
'()
(if (list? (car list))
(cons (replace var player (car list))
(replace var player (cdr list)))
(if (equal? var (car list))
(cons player (replace var player (cdr list)))
(cons (car list) (replace var player (cdr list)))))))
After these corrections, the OP code works for nested lists where the item to be replaced is a non-list. But, it fails when the item to be replaced is a list. This is because list elements encountered in the input are never checked for equality against var. Note also that it is a bad idea to use list as a formal parameter in Scheme functions; this shadows the built-in list function.
Here is an implementation that will replace both atoms and lists in the input list. Before checking whether the input is an atom, the function checks for equality with old. If the old value is not equal? to the current head value, then the function checks whether the current head value is an atom. If it is, then that atom (which was not equal? to old) is consed onto the result of calling replace on the tail; note that empty lists are considered atoms ('() is both a list and an atom) and have already been handled at this stage. Otherwise, the current head is a non-empty list, and the function descends into both the head and the tail.
Here atom? is used to distinguish between non-empty lists and atoms, with '() being considered an atom. Some Schemes include a definition for atom?, but it is not in R5RS or R6RS Standard Scheme. You can define it yourself if needed:
(define (atom? x)
(not (pair? x)))
Or you could just use (not (pair? head)) in place of (atom? head) in the code below, which uses atom? because the name seems more descriptive. A let expression is used to reduce the number of calls to car and cdr, and to clarify the intent of the recursive calls to replace:
(define (replace old new xs)
(if (null? xs)
xs
(let ((head (car xs))
(tail (cdr xs)))
(cond ((equal? head old)
(cons new (replace old new tail)))
((atom? head)
(cons head (replace old new tail)))
(else
(cons (replace old new head)
(replace old new tail)))))))
Here are some sample interactions:
> (replace 'a 'x '(1 2 a 3 4 a))
(1 2 x 3 4 x)
> (replace 'a 'x '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 x (3 4 x (5 x (x (x)) 6 x) ()) x)
> (replace '() 'x '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 a (3 4 a (5 a (a (a)) 6 a) x) a)
> (replace '(5 a (a (a)) 6 a) 'x '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 a (3 4 a x ()) a)
> (replace '(5 a (a (a)) 6 a) '(x (x x)) '(1 2 a (3 4 a (5 a (a (a)) 6 a) ()) a))
(1 2 a (3 4 a (x (x x)) ()) a)
Related
I am building a function is Lisp ta reverses the first and last element of a list. I get that a list has a car and a cdr hence why there is a dot in my output. Is there a way to remove the dot?
(defun my-butlast (list)
(loop for l on list
while (cdr l)
collect (car l)))
(defun f-l-swap(list)
(append (last list)(cdr (my-butlast list))(car list))
)
(write(f-l-swap '(A B C D E)))
OUTPUT:
(E B C D . A)
append expects arguments to be lists. In your case (car list) is an atom. You have to change it to list if you want to stick with append. Ie:
(defun f-l-swap (list)
(append (last list)
(cdr (my-butlast list))
(list (car list))))
A list is a chain of cons pairs. eg. (1 2 3) is the visualization of (1 . (2 . (3 . ()))). In the event the last cdr is not () you have what we call a dotted list since then there is no simplified visualization of the last part. It has to be printed with a dot.
You have (E . (B . (C . (D . A)))) and want to have (E . (B . (C . (D . (A . ()))))). Do you see the difference? (car list) is not a list but one elment and that is why you get a dotted list.
Here are more sensible implementations of append and butlast:
(defun my-append (a b)
(if (null a)
b
(cons (car a) (my-append (cdr a) b))))
That only supports 2 arguments, but the idea for more is that it continues until you have consed all the previous lists and only have one left, which verbatim becomes the tail. Here is how that might look:
(defun my-append2 (x &rest xs)
(labels ((helper (x xs)
(cond ((null xs) x)
((null x) (helper (car xs) (cdr xs)))
(t (cons (car x) (helper (cdr x) xs))))))
(helper x xs)))
Here is butlast
(defun my-butlast (xs)
(if (null (cdr xs))
'()
(cons (car xs) (my-butlast (cdr xs)))))
Now, one should really do it with higher order functions or loop, but then you get the facts hidden how lists work. The code above shows you have they work.
I've just started learning Racket.
I have written this procedure:
#lang racket
(define split
(lambda (list)
(define plus-list '())
(define minus-list '())
(cond ((null? list) '())
(else
(do ([i (length list) (- i 1)])
((zero? i))
(define l (list-ref list i))
(define item (last-element-on-list l))
(cond ((= (cdr l '+)) (set! plus-list (cons list plus-list)))
((= (cdr l '-)) (set! minus-list (cons list minus-list))))
)
(cons plus-list minus-list)
)
)
)
)
And instead of using (list-ref lst i) inside de do I have defined a variable l:
(define (list-ref lst i) l)
But it seems that I cann't do that, because I get the error:
define: not allowed in an expression context in: (define l (list-ref
lst i))
But there are a lot of define inside the do.
If I remove all the define inside the do, I have to write a lot of code and it is not easier to read and understand:
(define split
(lambda (list)
(define plus-list '())
(define minus-list '())
(cond ((null? list) '())
(else
(do ([i (length list) (- i 1)])
((zero? i))
(cond ((= (cdr (last-element-on-list (list-ref list i)) '+)) (set! plus-list (cons (list-ref list i) plus-list)))
((= (cdr (last-element-on-list (list-ref list i)) '-)) (set! minus-list (cons (list-ref list i) minus-list))))
)
(cons plus-list minus-list)
)
)
)
)
How can I define a variable inside a do?
Reading your other question I see why you write the bolded expressions -
…
(cond ((= (cdr (last-element-on-list (list-ref list i)) '+))
(set! plus-list
(cons (list-ref list i) plus-list)))
((= (cdr (last-element-on-list (list-ref list i)) '-))
(set! minus-list
(cons (list-ref list i) minus-list))))
…
Your input list shown there is –
(define lst
'((n 25 f +)
(s 25 m +)
(ll 20 no -)))
Your split is inspecting the contents of each element of l. split has overstepped its boundaries and now it only works for lists containing elements of this particular structure. Along with set!, lack of else in a cond is typically an indication you're doing something wrong. You also call (cdr (last-element-of-list ...)). If last-element-of-list returns an atom, cdr would throw an error here.
Consider designing split in a more generic way –
(define (split proc l)
(define (loop l true false)
(cond ((null? l)
(cons true false))
((proc (car l))
(loop (cdr l)
(cons (car l) true)
false))
(else
(loop (cdr l)
true
(cons (car l) false)))))
(loop l '() '()))
(split (lambda (x) (> x 5))
'(1 5 3 9 7 0 8 3 2 6 4))
;; '((6 8 7 9) 4 2 3 0 3 5 1)
If our list contains different elements, we can still use the same split procedure –
(split (lambda (x) (eq? '+ (cadr x)))
'((1 +) (1 -) (2 +) (3 +) (2 -) (3 -) (4 +)))
;; '(((4 +) (3 +) (2 +) (1 +)) (3 -) (2 -) (1 -))
I think it's never too early to start learning continuation passing style. Below, return represents our continuation and defaults to cons, the same procedure we used to return the final result in our original implementation. Intuitively, a continuation represents "the next step" of the computation –
(define (split proc l (return cons)) ;; `return` is our continuation
(if (null? l)
;; base case: list is empty, return empty result
(return '() '())
;; inductive case: at least one `x`
(let* ((x (car l))
(bool (proc x)))
(split proc ;; tail recur with our proc
(cdr l) ;; ... a smaller list
(lambda (t f) ;; ... and "the next step"
(if bool ;; if `(proc x)` returned true
(return (cons x t) ;; ... cons the `x` onto the `t` result
f) ;; ... and leave the `f` the same
(return t ;; otherwise leave `t` the same
(cons x f)))))))) ;; ... and cons the `x` onto the `f` result
If we run our split procedure, you'll notice we get the same exact output as above. At first glance it looks like we made a mess of a nice program, however there's one distinct advantage of this implementation. Because the continuation is user-configurable, instead of cons, we could decide an entirely different fate for our two lists, t and f –
(split (lambda (x) (eq? '+ (cadr x)))
'((1 +) (1 -) (2 +) (3 +) (2 -) (3 -) (4 +))
(lambda (plus minus)
(printf "plus: ~a, minus: ~a\n" plus minus)))
;; plus: ((1 +) (2 +) (3 +) (4 +)), minus: ((1 -) (2 -) (3 -))
Note how plus and minus were given the respective results. We didn't have to pick apart an intermediate cons result. More intuitively, we want printf to be "the next step", but we only need to specify the first argument –
(split (lambda (x) (eq? '+ (cadr x)))
'((1 +) (1 -) (2 +) (3 +) (2 -) (3 -) (4 +))
(curry printf "plus: ~a, minus: ~a\n"))
;; plus: ((1 +) (2 +) (3 +) (4 +)), minus: ((1 -) (2 -) (3 -))
Now we've scratched the surface of functional style :D
do loops are not idiomatic Racket. They are inherited from Scheme, and for whatever reason, they don’t permit internal definitions. I have never once used a do loop in Racket, since the for comprehensions are more functional, and they’re just generally easier to work with. Plus, since they originate in Racket, not in Scheme, they support internal definitions as you’d expect.
You could write your split function using for/fold instead of do, which has the added advantage of not needing to use set! (and avoiding the quadratic access time of using list-ref instead of iterating through the list). I’m not completely sure what your split function is supposed to do, as even with the internal definition removed, it does not compile, but here’s my best guess at what you might be attempting to do:
(define (split lst)
(for/fold ([plus-lst '()]
[minus-lst '()])
([l (in-list lst)])
(define item (last l))
(cond
[(equal? item '+)
(values (cons l plus-lst) minus-lst)]
[(equal? item '-)
(values plus-lst (cons l minus-lst))]
[else
(values plus-lst minus-lst)])))
Aside from the obvious restructuring to use for/fold instead of do, this code also makes the following changes over your code:
It uses the built-in last function from racket/list to get the last element of a list.
It uses equal? instead of = to compare symbols, since = is specifically for comparing numbers.
It indents things properly and puts close parentheses in idiomatic locations.
I fixed your code using let, read documentation about let it's heavily used in Scheme/Racket. I haven't used Scheme lately so I couldn't explain it as well as it is in documentation.
Shortly it's local symbol definition/redefinition, and you can use symbol with value only in let body.
Short example on let
(define x 5)
(let ((x 10))
(display x)) # => 10
(display x) # => 5
(let ((y 1))
(display y)) # => 1
(display y) # = => (error) y: undefined
Your code fixed using let
(define split
(lambda (list)
(let ((plus-list '())
(minus-list '()))
(cond ((null? list) '())
(else
(do ([i (length list) (- i 1)])
((zero? i))
(let ((l (list-ref list i))
(item (last-element-on-list l)))
(cond ((= (cdr l '+)) (set! plus-list (cons list plus-list)))
((= (cdr l '-)) (set! minus-list (cons list minus-list))))))
(cons plus-list minus-list))))))
I wish to create a function in Scheme that takes in a predicate and a list of elements, and then outputs two separate lists. One with elements of the original list that MATCH the given predicate, and one with elements that DON'T match it.
The code I have right now I believe should isolate those which match the predicate and output a list of them but the code will not work.
(define tear
(lambda (pred xs)
(cond[(null? xs) '()]
[(list? (car xs))(cons((tear (pred (car xs)))(tear (pred (cdr xs)))))]
[(pred (car xs))(cons((car xs)(tear (pred (cdr xs)))))]
[else tear (pred (cdr xs))])))
(tear number? '(1 2 3 a b c))
The resulting output on my compiler is:
tear: arity mismatch;
the expected number of arguments does not match the given number
expected: 2
given: 1
arguments...:
#f
context...:
/home/jdoodle.rkt:2:4: tear
Command exited with non-zero status 1
Any help/info that you can give would be much appreciated.
Lets fix your code step by step. Adding indentation and whitespace to make it readable:
(define tear
(lambda (pred xs)
(cond
[(null? xs)
'()]
[(list? (car xs))
(cons ((tear (pred (car xs))) (tear (pred (cdr xs)))))]
[(pred (car xs))
(cons ((car xs) (tear (pred (cdr xs)))))]
[else
tear (pred (cdr xs))])))
(tear number? '(1 2 3 a b c))
The first problem I see is a problem of putting parentheses on the inside (around the arguments) of a function call instead on the outside. You do this with cons and with the recursive calls to tear. For instance in tear (pred (cdr xs)) you should move the first paren to before the function. Remember that parentheses in an expression almost always mean a function call in the shape of (function argument ...).
(cons (A B)) should be rewritten to (cons A B)
(tear (Pred Xs)) should be rewritten to (tear Pred Xs)
tear (Pred Xs) should be rewritten to (tear Pred Xs)
With these fixes your code looks like this:
(define tear
(lambda (pred xs)
(cond
[(null? xs)
'()]
[(list? (car xs))
(cons (tear pred (car xs)) (tear pred (cdr xs)))]
[(pred (car xs))
(cons (car xs) (tear pred (cdr xs)))]
[else
(tear pred (cdr xs))])))
(tear number? '(1 2 3 a b c))
;=> (1 2 3)
(tear number? '(1 2 "not a number" 3 4))
;=> (1 2 3 4)
However, it still does something weird when there's a nested list:
(tear list? (list '(1 2 3) "not a list" '(4 5)))
;=error> (() ())
To be consistent it should put the two lists into a list: ((1 2 3) (4 5)). To do that just remove the second cond case:
(define tear
(lambda (pred xs)
(cond
[(null? xs)
'()]
[(pred (car xs))
(cons (car xs) (tear pred (cdr xs)))]
[else
(tear pred (cdr xs))])))
(tear number? '(1 2 3 a b c))
;=> (1 2 3)
(tear list? (list '(1 2 3) "not a list" '(4 5)))
;=> ((1 2 3) (4 5))
It now seems to do exactly half of what you want. You want it to return two lists: one for elements that passed, and one for the elements that failed. It currently is returning just the first list.
The first thing you should do is document how it returns those two lists. Since there are always exactly two, you can return them as multiple values.
;; tear returns two values:
;; - a list of the elements of `xs` that passed `pred`
;; - a list of the elements of `xs` that failed `pred`
There are two parts of using multiple values: returning them and receiving them. Use (values A B) to return them, and (let-values ([(A B) ....]) ....) to match on a result, like the result of a recursive call.
That means every recursive call like this (f .... (tear ....) ....) should become
(let-values ([(A B) (tear ....)])
(values (f .... A ....)
???))
Applying that to your code:
;; tear returns two values:
;; - a list of the elements of `xs` that passed `pred`
;; - a list of the elements of `xs` that failed `pred`
(define tear
(lambda (pred xs)
(cond
[(null? xs)
(values '()
???)]
[(pred (car xs))
(let-values ([(A B) (tear pred (cdr xs))])
(values (cons (car xs) A)
???))]
[else
(let-values ([(A B) (tear pred (cdr xs))])
(values A
???))])))
Now to fill in the ??? holes, use examples.
(tear number? '()) should return two empty lists: () ()
(tear number? '(1 2)) should return a full list and an empty list: (1 2) ()
(tear number? '(a b)) should return an empty list and a full list: () (a b)
The first example corresponds to the first ??? hole, the second example corresponds to the second hole, and so on.
This tells us that the first hole should be filled in with '(), the second hole should be filled in with B, and the third hole should be filled in with (cons (car xs) B).
(define tear
(lambda (pred xs)
(cond
[(null? xs)
(values '() '())]
[(pred (car xs))
(let-values ([(A B) (tear pred (cdr xs))])
(values (cons (car xs) A)
B))]
[else
(let-values ([(A B) (tear pred (cdr xs))])
(values A
(cons (car xs) B)))])))
(tear number? '(1 2 3 a b c))
;=> (1 2 3)
; (a b c)
(tear list? (list '(1 2 3) "not a list" '(4 5)))
;=> ((1 2 3) (4 5))
; ("not a list")
This is a classic fold use-case. You're aggregating the list into two lists :
(define tear (lambda (pred lst)
(fold-right ; Aggregate over lst
(lambda (elem agg)
(let ((accepted (car agg))
(rejected (cadr agg)))
(if (pred elem)
; Create a new agg by adding the current element to the accepted list
`(,(cons elem accepted) ,rejected)
; Or, if the predicate rejected the element,
; Create a new agg by adding the current element to the rejected list
`(,accepted ,(cons elem rejected)))))
`(() ())
lst)))
So, if you use even? as your predicate, you can get:
> (tear even? `(1 2 3 4 5 6 7 8))
((2 4 6 8) (1 3 5 7))
Here's another way you can do it using continuation-passing style; this puts the recursive call in tail position.
(define (partition p xs (return list))
(if (null? xs)
(return null null)
(partition p
(cdr xs)
(lambda (t f)
(if (p (car xs))
(return (cons (car xs) t)
f)
(return t
(cons (car xs) f)))))))
(partition number? '())
;; => '(() ())
(partition number? '(a 1 b 2 c 3))
;; => '((1 2 3) (a b c))
(partition list? '(1 2 (3 4) (5 6) 7 8))
;; => '(((3 4) (5 6)) (1 2 7 8))
Above, we make use of Racket's default arguments. Below we show how to define partition using a helper function instead
;; procedure above, renamed to partition-helper
(define (partition-helper p xs return)
...)
;; new procedure without optional parameter
(define (partition p xs)
;; call helper with default continuation, list
(partition-helper p xs list))
Comments may help distill some of the style's mysterious nature
;; default continuation is `list`, the list constructor procedure
(define (partition p xs (return list))
(if (null? xs)
;; base case: empty list; return the empty result
(return null null)
;; inductive case: at least one x; recur on the tail...
(partition p
(cdr xs)
;; ...specifying how to continue the pending computation
(lambda (t f)
(if (p (car xs))
;; if predicate passes, cons x onto the t result
(return (cons (car xs) t)
f)
;; otherwise cons x onto the f result
(return t
(cons (car xs) f)))))))
#WillNess asks why we delay evaluating the predicate; I don't have a reason other than I think the readability above is pretty good. We can alter the implementation to check the predicate right away, if we please. The impact here is very subtle. If you don't see it, I encourage you to play pen-and-paper evaluator and compare the two processes to understand it.
;; default continuation is `list`, the list constructor procedure
(define (partition p xs (return list))
(if (null? xs)
;; base case: empty list; return the empty result
(return null null)
;; inductive case: at least one x; recur on the tail...
(partition p
(cdr xs)
;; ...specifying how to continue the pending computation
(if (p (car xs))
(lambda (t f)
;; if predicate passes, cons x onto the t result
(return (cons (car xs) t)
f))
(lambda (t f)
;; otherwise cons x onto the f result
(return t
(cons (car xs) f)))))))
I have a circular list, eg: #0=(1 2 3 4 . #0#).
What I want to do is to insert a new element (x) into this list so that the outcome is #0=(x 1 2 3 4 . #0#). I have been trying using this code (x is the circular list):
(define (insert! elm)
(let ((temp x))
(set-car! x elm)
(set-cdr! x temp)))
However, I think that set-cdr! is not working like I want it to. What am I missing here? Maybe I am way off?
The easiest way to prepend an element to a list is to modify the car of the list, and set the cdr of the list to a new cons whose car is the original first element of the list and whose cdr is the original tail of the list:
(define (prepend! x list) ; list = (a . (b ...))
(set-cdr! list (cons (car list) (cdr list))) ; list = (a . (a . (b ...)))
(set-car! list x)) ; list = (x . (a . (b ...)))
(let ((l (list 1 2 3)))
(prepend! 'x l)
(display l))
;=> (x 1 2 3)
Now, that will still work with circular lists, because the cons cell (i.e., pair) that is the beginning of the list remains the same, so the "final" cdr will still point back to object that is the beginning. To test this, though, we need some functions to create and sample from circular lists, since they're not included in the language (as far as I know).
(define (make-circular list)
(let loop ((tail list))
(cond
((null? (cdr tail))
(set-cdr! tail list)
list)
(else
(loop (cdr tail))))))
(define (take n list)
(if (= n 0)
'()
(cons (car list)
(take (- n 1)
(cdr list)))))
(display (take 10 (make-circular (list 1 2 3))))
;=> (1 2 3 1 2 3 1 2 3 1)
Now we can check what happens if we prepend to a circular list:
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)
Since you're trying to prepend an element to a circular list, you need to do two things:
Insert a new cons cell at the front of the list containing the additional element. This is easy because you can just perform a simple (cons elm x).
You also need to modify the recursive portion of the circular list to point at the newly created cons cell, otherwise the circular portion will only include the old parts of the list.
To perform the latter, you need a way to figure out where the "end" of the circular list is. This doesn't actually exist, since the list is, of course, circular, but it can be determined by performing an eq? check on each element of the list until it finds an element equal to the head of the list.
Creating a helper function to do this, a simple implementation of insert! would look like this:
(define (find-cdr v lst)
(if (eq? v (cdr lst)) lst
(find-cdr v (cdr lst))))
(define (insert! elm)
(set! x (cons elm x))
(set-cdr! (find-cdr (cdr x) (cdr x)) x))
Is it possible to add or remove elements in the middle of a linked list in Scheme? I can't seem to think of a way doing this with car/cdr/cons, but I reccon there must be a way to this.
If I have a list '(1 3 5 6), and I need to put in 4 between 5 and 6 for example, is this doable?
Adding an element at a given position was done in a previous answer. Removing an element at a given position is similar:
(define (delete-at k lst)
(cond ((null? lst)
'())
((zero? k)
(cdr lst))
(else
(cons (car lst)
(delete-at (sub1 k) (cdr lst))))))
Here are two versions:
; list-insert : value index list -> list
; return list where the ith element is x
(define (list-insert x i xs)
(if (= i 0)
(cons x xs)
(cons (first xs) (list-insert x (- i 1) (rest xs)))))
(define (list-insert/version2 x i xs)
(define-values (before after) (split-at xs i))
(append before (list x) after))
(list-insert/version2 'x 2 '(a b c d))
(list-insert 'x 2 '(a b c d))
Both versions will allocate a new list. For large lists it will become inefficient.