I've been trying to learn some programming on my own by working through the textbook How to Design Programs for Scheme. I've gotten through everything until now. Here's the problem:
9.5.5 Develop the function convert. It consumes a list of digits and
produces the corresponding number. The
first digit is the least significant,
and so on.
Following the first few steps, from data analysis to template, I end
up with this, the bare bones of a program:
;; A list-of-numbers is either 1. an empty list, empty, or 2. (cons n
lon) where n is a number and lon is a list of numbers
;; convert : lon -> number
;; to consume a lon and produce the corresponding number. The least
significant digit corresponds to the first number in the list, and so
on.
;; (= (convert (cons 1 (cons 9 (cons 10 (cons 99 empty))))) 991091)
(define (convert lon)
(cond
[(empty? lon)...]
[(cons? lon)...(first lon)...(convert (rest lon))...]))
How do I get past this stage to, as the book has it, "combining values"?
The one way I think could work is if I multiplied the first value by
10 to the power of the value's significance in the total number, e.g.,
(cons 1 (cons 9 empty)) => 1 * 10^(SIGNIFICANCE), where LEAST
SIGNIFICANCE would be 0. Using my limited understanding of
programming, I figure that requires some counter, where n increases by
one every time the function, in a manner of speaking, is called
recursively. But that looks to me to be an attempt to run two
recursions at the same time. Because expressions are evaluated
sequentially (obviously), you can't call the counter function as you
call the convert function.
So, can anyone help me solve this problem? I would prefer if you
solved this using natural recursion and the CONStructor for lists and
not lambda or other ideas the book hasn't addressed yet.
Thanks!
You don't need to do exponentiation - simple multiplication will do just fine.
(define (convert digits)
(cond
((empty? digits) 0)
(else (+ (* 10 (convert (rest digits))) (first digits)))
)
)
(convert '(1 2 3 4 5 6))
Or, another way of thinking about it:
(define (convert digits)
(convert-helper digits 1 0)
)
(define (convert-helper digits multiplier sofar)
(cond
((empty? digits) sofar)
(else
(convert-helper
(rest digits)
(* 10 multiplier)
(+ (* multiplier (first digits)) sofar)
)
)
)
)
(convert '(1 2 3 4 5 6))
Here's a tail recursive version:
(define (convert lon)
(let rec ((i 0)
(n 0)
(lon lon))
(cond ((empty? lon) n)
(else (rec (+ i 1)
(+ n (* (first lon) (expt 10 i)))
(rest lon))))))
Related
****What I tried****
(define(help num)
(if(= num 1)
num
(cons(num (help( - num 1))))))
;i called this defination in the bottom one
(define (list-expand L)
(cond
[(empty? L)'()]
[(=(car L)1)(cons(car L)(list-expand (cdr L)))]
[(>(car L)1) (cons(help(car L)(list-expand(cdr L))))]))
In the help procedure, the base case is incorrect - if the output is a list then you must return a list. And in the recursive step, num is not a procedure, so it must not be surrounded by brackets:
(define (help num)
(if (<= num 0)
'()
(cons num (help (- num 1)))))
And in list-expand, both recursive steps are incorrect. You just need to test whether the list is empty or not, calling help with the correct number of parameters; use append to combine the results, because we're concatenating sublists together:
(define (list-expand L)
(if (empty? L)
'()
(append (help (car L)) (list-expand (cdr L)))))
That should work as expected, but please spend some time studying Scheme's syntax, you still have trouble with the basics, for instance, when and where to use brackets...
(list-expand '(3 2))
=> '(3 2 1 2 1)
Just for fun - a non-recursive solution in Racket:
(append-map (lambda (n) (stream->list (in-range n 0 -1))) '(3 2))
;; or:
(append-map (lambda (n) (for/list ((x (in-range n 0 -1))) x)) '(3 2))
Returning:
'(3 2 1 2 1)
I am trying to create a list of n elements. It must produce this output:
(my-list 5)
>> 0 1 2 3 4
I have the function below:
(define (my-list n)
(cond
((<= n 0) '())
(else (reverse-list (cons (- n 1)
(my-list(- n 1)))))
)
)
and this is producing
(my-list 10)
>>(8 6 4 2 0 1 3 5 7 9)
I understand this is due to reversing the list at every recursive call, but I am not sure what is the correct way. Also my reverse-list is working fine.
Thanks in advance!
A standard idiom in Scheme 'build-and-reverse' suggests you only reverse the list once, at the very end, when its reverse has been completely built (thus reducing the complexity down to O(N) from quadratic.)
So yes, you end up in a tail call to reverse but the list should be built without doing it. Scheme has plenty of local recursive binding constructs.
But.
If you build a range starting with the largest value (that should be one greater than the last element to the list) you don't need to reverse it in the end, at each iteration step you decrease a counter and prepend its new value to those already accumulated:
(define (range n)
(let rng ((m (- n 1)) (ret-val '())) ; named-let is very useful for small local recursive closures
(if (< m 0) ; that original (<= n 0) check is also handled here
ret-val ; here, the result is returned; note we don't need to reverse it
(rng (- m 1) (cons m ret-val))))))
(display (range 10))
(newline)
prints
(0 1 2 3 4 5 6 7 8 9)
Or, to demonstrate the build-and-reverse, we can start with the lowest value:
(define (range-asc n)
(let rng ((m 0) (ret-val '()))
(if (= m n)
(reverse ret-val) ; since we started from zero, we need to reverse it
(rng (+ m 1) (cons m ret-val)))))
(Looks like I still remember/can recover some Scheme. :-O)
First of all, your code. Properly formatted it should look something like:
(define (my-list n)
(cond ((<= n 0) '())
(else (reverse-list (cons (- n 1)
(my-list (- n 1)))))))
Problem you have, is reverse-list call. It happens every time you add new element to the list. You can fix it in many ways, but simple solution is to wrap your recursive code into local function, and do some additional operations (reverse in your case) when it returns.
(define (my-list n)
(define (build-list m)
(cond ((<= m 0) '())
(else (cons (- m 1)
(build-list (- m 1))))))
(reverse-list (build-list n)))
So, inside my-list function, first we define recursive part as a local function build-list. This is exactly your code, but with call to reverse-list removed. This part will build your list, but as you know, in reverse order. But that is no longer a problem, since we can reverse it when local function returns.
I have a doubt, I'm using Racket, and I wanna count the digits of a list, but I can't. I try with length but it doesn't work as I want because
(countDigits '(4 5 6 78)) > 5
the answer has to be 5 but, i don't know how to, i have a code for count digits in a number but I don't knowhow to do it in a list.
¿How could I do it?
Here's a possible solution:
(define (countDigits lst)
(apply +
(map (compose string-length number->string)
lst)))
Explanation:
For each number in the list, we convert it to a string
Then, we obtain the length of each string - that will tell us the number of digits
Finally, we add together all the lengths
For example:
(countDigits '(4 5 6 78))
=> 5
A more naive example that wouldn't make your professor look twice :)
Regular Recursion:
(define (countDigits list-of-digits)
(cond [(empty? list-of-digits) 0]
[else (+ 1 (countDigits (rest list-of-digits)))]))
Tail Recursion:
(define (countDigits list-of-digits sum)
(cond [(empty? list-of-digits) sum]
[else (countDigits (rest list-of-digits) (+ 1 sum))]))
I'm trying to create a function that takes in user input, x, and displays all of the numbers from 1 up to x. Not quite sure where to go from here:
(define (iota x)
(if (>= x 1)
(display
;; Takes a number n
;; and returns a list with 1..n
;; in order.
(define (make-list n)
(let loop ((n n) (accumulator '()))
(if (zero? n)
accumulator
(loop (- n 1) (cons n accumulator)))))
;; prints data and adds
;; a newline
(define (println x)
(display x)
(newline))
;; prints 1..n by applying println
;; for-each element over the list 1..n
(define (iota n)
(for-each println (make-list n)))
Basically you want to use recursion. So think of it was counting up. As you count up either you've added enough numbers and you are done building your list or you need to add the current number to your list and go on to the next number.
Look at the following code:
(define (range-2 next-num max-num cur-list)
;;if we've added enough numbers return
(if (> next-num max-num)
cur-list
;; otherwise add the current number to the list and go onto the next one
(range-2
(+ 1 next-num)
max-num
(append cur-list (list next-num))
)))
But to get the function you wanted you need to start off with the constants you specified (ie 1), so lets create a convenience function for calling range with the starter values you need to set up the recursion, sometimes called priming the recursion:
(define (range X)
(range-2 1 X `() ))
You could do it without the second function using lambda, but this is pretty common style from what I've seen.
Once you've constructed a list of the numbers you need you just display it using
(display (range 10))
If you're using Racket you're in luck, you can use iterations and comprehensions, for instance in-range:
(define (iota x)
(for ([i (in-range 1 (add1 x))])
(printf "~a " i)))
Or for a more standard solution using explicit recursion - this should work in most interpreters:
(define (iota x)
(cond ((positive? x)
(iota (- x 1))
(display x)
(display " "))))
Either way, it works as expected:
(iota 10)
=> 1 2 3 4 5 6 7 8 9 10
(define iota2
(lambda (y)
(let loop ((n 1))
(if (<= n y)
(cons n (loop (+ n 1)))
'()))))
(define (iota x)
(if (>= x 1)
(begin
(iota (- x 1))
(display x)
(newline))))
Assume I have the list (3 1 4 5 2) with the name "numbers". I am looking for a command that will reverse the list from index 0 up to an arbitrary index, i.e. (reverse numbers 2) which will give the new list as (4 1 3 5 2).
I've tried googling, but could not find a suitable function and I'm too much of a newbie to write the function myself at this stage.
Thank you.
Simple CL version based on the libary functions:
(defun reverse-first-n (list n)
(nreconc (subseq list 0 n) (nthcdr n list)))
This is memory-optimal, i.e., it does not allocate unnecessarily:
no need to copy the tail, thus nthcdr instead of subseq
revappend copies the 1st argument which is a fresh list anyway, so nreconc is more economical.
This version is speed-suboptimal, because it traverses list to the nth position 3 times - once in subseq, once in nthcdr, and then once in nreconc.
Here is the optimal verion:
(defun reverse-first-n (list n)
(if (or (= n 0) (= n 1))
list
(do* ((tail (list (pop list)))
(head tail (cons (pop list) head))
(count (1- n) (1- count)))
((zerop count)
(setf (cdr tail) list)
head))))
Note that there is very little chance that this is the performance bottleneck in your code. My main purpose in providing the second version is to show how much time and effort the extensive and well-designed CL library saves you.
Which dialect of Lisp are you using? Here's a Scheme solution (using SRFI 1):
(require srfi/1) ; assuming you're using Racket
(define (reverse-first-n lst n)
(call-with-values (lambda ()
(split-at lst n))
append-reverse!))
I made the function really "reverse the first n elements" like your title says, and unlike your question description. So for example:
> (reverse-first-n '(3 1 4 5 2) 2)
'(1 3 4 5 2)
> (reverse-first-n '(3 1 4 5 2) 3)
'(4 1 3 5 2)
As requested by the OP, here's a Common Lisp version. sds already posted a pretty decent version, so the version I'm writing is a more direct port of my Scheme solution (append-reverse! ⇒ nreconc; call-with-values ⇒ multiple-value-call; and I'm porting SRFI 1's split-at to CL):
(defun split-at (list n)
(if (zerop n)
(values '() list)
(multiple-value-bind (prefix suffix)
(split-at (cdr list) (1- n))
(values (cons (car list) prefix) suffix))))
(defun reverse-first-n (list n)
(multiple-value-call #'nreconc (split-at list n)))
(Why split-at? Its purpose is to provide both the take (subseq) and drop (nthcdr) with only one traversal of the input list.)