(define (sqr-tail lst)
(define (helper lst res)
(if (null? lst)
res
(cond ((list? (car lst))
(helper (cdr lst)
(cons (helper (car lst) ())
result)))
(else (helper (cdr lst)
(cons (expt (car lst) 2) res))))))
(helper lst ()))
I have this tail recursion function in scheme which sqr every element in the list, but unfortunately the result is reversed to what I suppose to output.
for input :
> (sqr-tail (list 1 2 4 3 (list 1 2 (list 1)) 3 3))
the output :
< (9 9 ((1) 4 1) 9 16 4 1)
thanks.
This is something that is inherent in the way Lisp/Scheme lists work: because there are only really conses, the way to build up lists is backwards. So the common tail-recursive-loop-with-an-accumulator approach as you've used ends up building the result backwards. The simple answer to this is that you need to reverse the result when you return it, and in your case, since you are recursing (not tail-recursing) into nested lists as well you need to reverse them as well of course.
Here is a somewhat cleaned-up and error-protected version of your original function (note this was written in Racket -- it may not be quite legal Scheme, but it is close):
(define (square-nested-list/reversed l)
(define (snl-loop lt accum)
(cond [(null? lt)
accum]
[(cons? lt)
(let ([head (car lt)]
[tail (cdr lt)])
(cond [(list? head)
(snl-loop tail (cons (snl-loop head '())
accum))]
[(number? head)
(snl-loop tail (cons (* head head) accum))]
[else (error "mutant horror death")]))]
[else (error "mutant death horror")]))
(snl-loop l '()))
So to get the result forwards we need to reverse the accumulator when we return it. This is a very small change to the above function:
(define (square-nested-list/forward l)
(define (snl-loop lt accum)
(cond [(null? lt)
(reverse accum)]
[(cons? lt)
(let ([head (car lt)]
[tail (cdr lt)])
(cond [(list? head)
(snl-loop tail (cons (snl-loop head '())
accum))]
[(number? head)
(snl-loop tail (cons (* head head) accum))]
[else (error "mutant horror death")]))]
[else (error "mutant death horror")]))
(snl-loop l '()))
If you want to be annoyingly clever and purist you can now notice that the tail-recursive-loop-with-accumulator approach produces results in reverse, so the trivial case of it is, in fact, reverse:
(define (square-nested-list/forward/stupidly-purist l)
(define (rev l)
(define (rev-loop lt a)
(if (null? lt) a (rev-loop (cdr lt) (cons (car lt) a))))
(rev-loop l '()))
(define (snl-loop lt accum)
(cond [(null? lt)
(rev accum)]
[(cons? lt)
(let ([head (car lt)]
[tail (cdr lt)])
(cond [(list? head)
(snl-loop tail (cons (snl-loop head '())
accum))]
[(number? head)
(snl-loop tail (cons (* head head) accum))]
[else (error "mutant horror death")]))]
[else (error "mutant death horror")]))
(snl-loop l '()))
People who do this are generally just trying to score points on the internet though (there are even more stupidly pure approaches for which you get more points).
And here are the results of calling those three functions:
> (define test-data '((1 2 3) (4 5) 6))
> (displayln (square-nested-list/reversed test-data))
(36 (25 16) (9 4 1))
> (displayln (square-nested-list/forward test-data))
((1 4 9) (16 25) 36)
> (displayln (square-nested-list/forward/stupidly-purist test-data))
((1 4 9) (16 25) 36)
Some other approaches
One issue with this 'reverse the result' is that it involves walking the result to reverse it, and also making a copy of it. Once upon a time this was something that was a real problem, because machines had only a tiny amount of memory and were very slow. Indeed, if your lists are enormous it still is a problem. More commonly it is a problem which exists in the minds of people who either, like me, remember machines which were very slow and had only tiny memory, or whose minds have been damaged by languages which encourage you to behave as if you were using such machines ('C programmers know the cost of everything but the value of nothing').
One partial answer to this problem offered by older Lisps is a function which is like reverse but works destructively: it reverses a list in place, destroying the original structure. This function is called nreverse in Common Lisp. If it existed in Scheme it would be called reverse! I suppose.
A more complete answer is to build the list forwards in the first place. You do this by trickery involving keeping a reference to the final cons of the list, and repeatedly replacing its cdr with a new final cons whose car is the object you are collecting. If you want to do this without your code looking horrible you need to use a macro: the one I wrote (for Common Lisp, not Scheme) was called collecting as it collected lists forwards. There are many others. Note that this approach requires mutable conses and also is not clearly efficient in the presence of modern garbage collectors.
Macros like collecting still have their place I think: not because they make your code faster, but because they can make it clearer: if you want collect some results into a list, then do that, don't do this weird reversing thing.
You are almost there.
All you need to do is reverse the return value for each sublist:
(defun sqr-tail (lst)
(labels ((helper (lst res)
(cond ((null lst)
(reverse res))
((listp (car lst))
(helper (cdr lst)
(cons (helper (car lst) ())
res)))
(t (helper (cdr lst)
(cons (expt (car lst) 2) res))))))
(helper lst ())))
(sqr-tail (list 1 2 4 3 (list 1 2 (list 1)) 3 3))
==> (1 4 16 9 (1 4 (1)) 9 9)
or, in scheme:
(define (sqr-tail lst)
(define (helper lst res)
(cond ((null? lst)
(reverse res))
((list? (car lst))
(helper (cdr lst)
(cons (helper (car lst) ())
res)))
(else (helper (cdr lst)
(cons (expt (car lst) 2) res)))))
(helper lst ()))
Related
I have a recursive code and need to terminate it when condition is fullfilled. I am capable of display the list when the condition, but then there are another calls on stack that I don't need to process that doesn't let me to return the list.
A variation of Sylwester's solution:
(define (example n)
(call-with-current-continuation
(lambda (return)
(let loop ([n 0])
(if (= n 5) ; done
(return 'the-result)
(loop (+ n 1)))))))
(example 10)
Using the continuation in this way allows one to use an escape continuation instead of a full continuation with call/ec (if your implementation has escape continuations).
The best way to do it is by using an accumulator. Aborting is then just not recursing.
(define (copy-unless-contains-5 lst)
(define (helper lst acc)
(cond
((null? lst) (reverse acc))
((equal? (car lst) 5) #f)
(else (helper (cdr lst) (cons (car lst) acc)))))
(helper lst '()))
If you are recursing with a continuation and that is the optimum way of doing it, then call-with-current-continuation can give you a way to abort waiting continuations and choose what to return.
(define (copy-unless-contains-5 lst)
(call-with-current-continuation
(lambda (abort)
(define (helper lst)
(cond
((null? lst) '())
((equal? (car lst) 5) (abort #f))
(else (cons (car lst) (helper (cdr lst))))))
(helper lst))))
Needless to say this last version is overly complicated. Both work the same:
(copy-unless-contains-5 '(1 2 3 4)) ; ==> (1 2 3 4)
(copy-unless-contains-5 '(1 2 5 3 4)) ; ==> #f
Consider:
(define (nested-reverse lst)
(cond ((null? lst) '())
((list? (car lst)) (nested-reverse (car lst)))
(else
(cons (nested-reverse (cdr lst))
(list (car lst))))))
When I input,
(nested-reverse '((a b c) 42))
it gives me ((() 42) (a b c)). It's supposed to give me (42 (c b a)). How I would change my code so that the nested lists also get reversed?
Keep in mind that a list (1 2 3) is (cons 1 (cons 2 (cons 3 '()))). Using append is a very poor choice on how to reverse a list since append is implemented like this:
(define (append lst1 lst2)
(if (null? lst1)
lst2
(cons (car lst1) (append (cdr lst1) lst2))))
A list can be iterated from the first element towards the end while it can only be made in reverse. Thus the obvious none recursive reverse would look like something like this:
(define (simple-reverse lst)
(let loop ((lst lst) (result '()))
(if (null? lst)
result
(loop (cdr lst) (cons (car lst) result)))))
To make it work for nested list you check if you need to reverse (car lst) by checking of it's a list or not and use the same procedure as you are creating to do the reverse on the element as well. Other than that it's very similar.
I am trying to solve the exercise 2.20 from SICP book. The exercise -
Write a procedure same-parity that takes one or more integers and returns a list of
all the arguments that have the same even-odd parity as the first argument. For example,
(same-parity 1 2 3 4 5 6 7)
(1 3 5 7)
(same-parity 2 3 4 5 6 7)
(2 4 6)
My code -
(define same-parity (lambda (int . l)
(define iter-even (lambda (l2 rl)
(cons ((null? l2) rl)
((even? (car l2))
(iter-even (cdr l2) (append rl (car l2))))
(else (iter-even (cdr l2) rl)))))
(define iter-odd (lambda (l2 rl)
(cons ((null? l2) rl)
((odd? (car l2))
(iter-odd (cdr l2) (append rl (car l2))))
(else (iter-odd (cdr l2) rl)))))
(if (even? int) (iter-even l (list int))
(iter-odd l (list int)))))
For some reason I am getting an error saying "The object (), passed as the first argument to cdr, is not the correct type". I tried to solve this for more than two hours, but I cant find any reason why it fails like that. Thanks for hlep.
Try this:
(define same-parity
(lambda (int . l)
(define iter-even
(lambda (l2 rl)
(cond ((null? l2) rl)
((even? (car l2))
(iter-even (cdr l2) (append rl (list (car l2)))))
(else (iter-even (cdr l2) rl)))))
(define iter-odd
(lambda (l2 rl)
(cond ((null? l2) rl)
((odd? (car l2))
(iter-odd (cdr l2) (append rl (list (car l2)))))
(else (iter-odd (cdr l2) rl)))))
(if (even? int)
(iter-even l (list int))
(iter-odd l (list int)))))
Explanation:
You are using cons instead of cond for the different conditions
in the part where append is called, the second argument must be a proper list (meaning: null-terminated) - but it is a cons-pair in your code. This was causing the error, the solution is to simply put the second element inside a list before appending it.
I must say, using append to build an output list is frowned upon. You should try to write the recursion in such a way that cons is used for creating the new list, this is more efficient, too.
Some final words - as you're about to discover in the next section of SICP, this problem is a perfect fit for using filter - a more idiomatic solution would be:
(define (same-parity head . tail)
(if (even? head)
(filter even? (cons head tail))
(filter odd? (cons head tail))))
First, I check the first element in the list. If it is even, I call the procedure that forms a list out of only the even elements. Else, I call the procedure that forms a list out of odd elements.
Here's my code
(define (parity-helper-even B)(cond
((= 1 (length B)) (cond
((even? (car B)) B)
(else '())
))
(else (cond
((even? (car B)) (append (list (car B)) (parity-helper-even (cdr B))))
(else (parity-helper-even(cdr B)))
))))
(define (parity-helper-odd B)(cond
((= 1 (length B)) (cond
((odd? (car B)) B)
(else '())
))
(else (cond
((odd? (car B)) (append (list (car B)) (parity-helper-odd (cdr B))))
(else (parity-helper-odd (cdr B)))
))))
(define (same-parity first . L) (cond
((even? first) (parity-helper-even (append (list first) L)))
(else (parity-helper-odd (append (list first) L)))))
(same-parity 1 2 3 4 5 6 7)
;Output (1 3 5 7)
While you are traversing the list, you might as well just split it into even and odd parities. As the last step, choose the one you want.
(define (parities args)
(let looking ((args args) (even '()) (odd '()))
(if (null? args)
(values even odd)
(let ((head (car args)))
(if (even? head)
(looking (cdr args) (cons head even) odd)
(looking (cdr args) even (cons head odd)))))))
(define (same-parity head . rest)
(let-values ((even odd) (parities (cons head rest)))
(if (even? head)
even
odd)))
Except for homework assignments, if you are going to look for one then you are likely to need the other. Said another way, you'd find yourself using parities more frequently in practice.
You could simply filter elements by parity of first element:
(define (same-parity x . y)
(define (iter z filter-by)
(cond ((null? z) z)
((filter-by (car z))
(cons (car z) (iter (cdr z) filter-by)))
(else (iter (cdr z) filter-by))))
(iter (cons x y) (if (even? x) even? odd?)))
And try:
(same-parity 1 2 3 4 5 6 7)
(same-parity 2 3 4 5 6 7)
What it the proper way to sort a list with values in Scheme? For example I have the values which are not ordered:
x1, x5, x32 .... xn
or
3, 4, 1, 3, 4, .. 9
First I want to for them by increase number and display them in this order:
x1, xn, x2, xn-1
or
1, 6, 2, 5, 3, 4
Any help will be valuable.
This is the same question you posted before, but with a small twist. As I told you in the comments of my answer, you just have to sort the list before rearranging it. Here's a Racket solution:
(define (interleave l1 l2)
(cond ((empty? l1) l2)
((empty? l2) l1)
(else (cons (first l1)
(interleave l2 (rest l1))))))
(define (zippy lst)
(let-values (((head tail) (split-at
(sort lst <) ; this is the new part
(quotient (length lst) 2))))
(interleave head (reverse tail))))
It works as expected:
(zippy '(4 2 6 3 5 1))
=> '(1 6 2 5 3 4)
This R6RS solution does what Chris Jester-Young proposes and it really is how to do it the bad way. BTW Chris' and Óscar's solutions on the same question without sorting is superior to this zippy procedure.
#!r6rs
(import (rnrs base)
(rnrs sorting)) ; list-sort
(define (zippy lis)
(let loop ((count-down (- (length lis) 1))
(count-up 0))
(cond ((> count-up count-down) '())
((= count-up count-down) (cons (list-ref lis count-down) '()))
(else (cons (list-ref lis count-down)
(cons (list-ref lis count-up)
(loop (- count-down 1)
(+ count-up 1))))))))
(define (sort-rearrange lis)
(zippy (list-sort < lis)))
Here is a simple, tail-recursive approach that uses a 'slow/fast' technique to stop the recursion when half the list is traversed:
(define (interleave l)
(let ((l (list-sort < l)))
(let merging ((slow l) (fast l) (revl (reverse l)) (rslt '()))
(cond ((null? fast)
(reverse rslt))
((null? (cdr fast))
(reverse (cons (car slow) rslt)))
(else
(merging (cdr slow) (cddr fast) (cdr revl)
(cons (car revl) (cons (car slow) rslt))))))))
So, you don't mind slow and just want a selection-based approach, eh? Here we go....
First, we define a select1 function that gets the minimum (or maximum) element, followed by all the other elements. For linked lists, this is probably the simplest approach, easier than trying to implement (say) quickselect.
(define (select1 lst cmp?)
(let loop ((seen '())
(rest lst)
(ext #f)
(extseen '()))
(cond ((null? rest)
(cons (car ext) (append-reverse (cdr extseen) (cdr ext))))
((or (not ext) (cmp? (car rest) (car ext)))
(let ((newseen (cons (car rest) seen)))
(loop newseen (cdr rest) rest newseen)))
(else
(loop (cons (car rest) seen) (cdr rest) ext extseen)))))
Now actually do the interweaving:
(define (zippy lst)
(let recur ((lst lst)
(left? #t))
(if (null? lst)
'()
(let ((selected (select1 lst (if left? < >))))
(cons (car selected) (recur (cdr selected) (not left?)))))))
This approach is O(n²), whereas the sort-and-interleave approach recommended by everybody else here is O(n log n).
In an application I'm working on in Racket I need to take a list of numbers and partition the list into sub-lists of consecutive numbers:
(In the actual application, I'll actually be partitioning pairs consisting of a number and some data, but the principle is the same.)
i.e. if my procedure is called chunkify then:
(chunkify '(1 2 3 5 6 7 9 10 11)) -> '((1 2 3) (5 6 7) (9 10 11))
(chunkify '(1 2 3)) -> '((1 2 3))
(chunkify '(1 3 4 5 7 9 10 11 13)) -> '((1) (3 4 5) (7) (9 10 11) (13))
(chunkify '(1)) -> '((1))
(chunkify '()) -> '(())
etc.
I've come up with the following in Racket:
#lang racket
(define (chunkify lst)
(call-with-values
(lambda ()
(for/fold ([chunk '()] [tail '()]) ([cell (reverse lst)])
(cond
[(empty? chunk) (values (cons cell chunk) tail)]
[(equal? (add1 cell) (first chunk)) (values (cons cell chunk) tail)]
[else (values (list cell) (cons chunk tail))])))
cons))
This works just fine, but I'm wondering given the expressiveness of Racket if there isn't a more straightforward simpler way of doing this, some way to get rid of the "call-with-values" and the need to reverse the list in the procedure etc., perhaps some way comepletely different.
My first attempt was based very loosely on a pattern with a collector in "The Little Schemer" and that was even less straightforward than the above:
(define (chunkify-list lst)
(define (lambda-to-chunkify-list chunk) (list chunk))
(let chunkify1 ([list-of-chunks '()]
[lst lst]
[collector lambda-to-chunkify-list])
(cond
[(empty? (rest lst)) (append list-of-chunks (collector (list (first lst))))]
[(equal? (add1 (first lst)) (second lst))
(chunkify1 list-of-chunks (rest lst)
(lambda (chunk) (collector (cons (first lst) chunk))))]
[else
(chunkify1 (append list-of-chunks
(collector (list (first lst)))) (rest lst) list)])))
What I'm looking for is something simple, concise and straightforward.
Here's how I'd do it:
;; chunkify : (listof number) -> (listof (non-empty-listof number))
;; Split list into maximal contiguous segments.
(define (chunkify lst)
(cond [(null? lst) null]
[else (chunkify/chunk (cdr lst) (list (car lst)))]))
;; chunkify/chunk : (listof number) (non-empty-listof number)
;; -> (listof (non-empty-listof number)
;; Continues chunkifying a list, given a partial chunk.
;; rchunk is the prefix of the current chunk seen so far, reversed
(define (chunkify/chunk lst rchunk)
(cond [(and (pair? lst)
(= (car lst) (add1 (car rchunk))))
(chunkify/chunk (cdr lst)
(cons (car lst) rchunk))]
[else (cons (reverse rchunk) (chunkify lst))]))
It disagrees with your final test case, though:
(chunkify '()) -> '() ;; not '(()), as you have
I consider my answer more natural; if you really want the answer to be '(()), then I'd rename chunkify and write a wrapper that handles the empty case specially.
If you prefer to avoid the mutual recursion, you could make the auxiliary function return the leftover list as a second value instead of calling chunkify on it, like so:
;; chunkify : (listof number) -> (listof (non-empty-listof number))
;; Split list into maximal contiguous segments.
(define (chunkify lst)
(cond [(null? lst) null]
[else
(let-values ([(chunk tail) (get-chunk (cdr lst) (list (car lst)))])
(cons chunk (chunkify tail)))]))
;; get-chunk : (listof number) (non-empty-listof number)
;; -> (values (non-empty-listof number) (listof number))
;; Consumes a single chunk, returns chunk and unused tail.
;; rchunk is the prefix of the current chunk seen so far, reversed
(define (get-chunk lst rchunk)
(cond [(and (pair? lst)
(= (car lst) (add1 (car rchunk))))
(get-chunk (cdr lst)
(cons (car lst) rchunk))]
[else (values (reverse rchunk) lst)]))
I can think of a simple, straightforward solution using a single procedure with only primitive list operations and tail recursion (no values, let-values, call-with-values) - and it's pretty efficient. It works with all of your test cases, at the cost of adding a couple of if expressions during initialization for handling the empty list case. It's up to you to decide if this is concise:
(define (chunkify lst)
(let ((lst (reverse lst))) ; it's easier if we reverse the input list first
(let loop ((lst (if (null? lst) '() (cdr lst))) ; list to chunkify
(cur (if (null? lst) '() (list (car lst)))) ; current sub-list
(acc '())) ; accumulated answer
(cond ((null? lst) ; is the input list empty?
(cons cur acc))
((= (add1 (car lst)) (car cur)) ; is this a consecutive number?
(loop (cdr lst) (cons (car lst) cur) acc))
(else ; time to create a new sub-list
(loop (cdr lst) (list (car lst)) (cons cur acc)))))))
Yet another way to do it.
#lang racket
(define (split-between pred xs)
(let loop ([xs xs]
[ys '()]
[xss '()])
(match xs
[(list) (reverse (cons (reverse ys) xss))]
[(list x) (reverse (cons (reverse (cons x ys)) xss))]
[(list x1 x2 more ...) (if (pred x1 x2)
(loop more (list x2) (cons (reverse (cons x1 ys)) xss))
(loop (cons x2 more) (cons x1 ys) xss))])))
(define (consecutive? x y)
(= (+ x 1) y))
(define (group-consecutives xs)
(split-between (λ (x y) (not (consecutive? x y)))
xs))
(group-consecutives '(1 2 3 5 6 7 9 10 11))
(group-consecutives '(1 2 3))
(group-consecutives '(1 3 4 5 7 9 10 11 13))
(group-consecutives '(1))
(group-consecutives '())
I want to play.
At the core this isn't really anything that's much different from what's
been offered but it does put it in terms of the for/fold loop. I've
grown to like the for loops as I think they make for much
more "viewable" (not necessarily readable) code. However, (IMO --
oops) during the early stages of getting comfortable with
racket/scheme I think it's best to stick to recursive expressions.
(define (chunkify lst)
(define-syntax-rule (consecutive? n chunk)
(= (add1 (car chunk)) n))
(if (null? lst)
'special-case:no-chunks
(reverse
(map reverse
(for/fold ([store `((,(car lst)))])
([n (cdr lst)])
(let*([chunk (car store)])
(cond
[(consecutive? n chunk)
(cons (cons n chunk) (cdr store))]
[else
(cons (list n) (cons chunk (cdr store)))])))))))
(for-each
(ƛ (lst)
(printf "input : ~s~n" lst)
(printf "output : ~s~n~n" (chunkify lst)))
'((1 2 3 5 6 7 9 10 11)
(1 2 3)
(1 3 4 5 7 9 10 11 13)
(1)
()))
Here's my version:
(define (chunkify lst)
(let loop ([lst lst] [last #f] [resint '()] [resall '()])
(if (empty? lst)
(append resall (list (reverse resint)))
(begin
(let ([ca (car lst)] [cd (cdr lst)])
(if (or (not last) (= last (sub1 ca)))
(loop cd ca (cons ca resint) resall)
(loop cd ca (list ca) (append resall (list (reverse resint))))))))))
It also works for the last test case.