DrRacket Using accumulator as List-ref index - list

I am trying to write a function that take a list and iterates over each element in the list if the number is even I want that number to be added to the previous number in the list.
I was thinking an accumulator will count up from 0 with each iteration giving a position for each element in the list.
If the number in the list is even I want to add that number to the previous number in the list.
Hence why I am trying to use the accumulator as an index for list-ref. I don't know how to write it to get the accumulator value for the previous iteration (+ i (list-ref a-list(- acc 1)))?
(define loopl (lambda (l)
(for/fold
([acc 0])([i l])
(cond
[(even? i)(+ i (list-ref (- acc 1) l))]
enter image description here

The question is not quite clear about the value to be returned by this function:
this answer assumes that it is a total of even elements together with their previous elements.
The function is developed using the
HtDF (How to Design Functions)
design method with a BSL (Beginning Student language) in DrRacket.
Start with a stub, incorporating signature and purpose, and a minimal "check-expect" example:
(Note: layout differs slightly from HtDF conventions)
(define (sum-evens-with-prev xs) ;; (Listof Integer) -> Integer ; *stub define* ;; *signature*
;; produce total of each even x with its previous element ; *purpose statement*
0) ; *stub body* (a valid result)
(check-expect (sum-evens-with-prev '()) 0) ; *minimal example*
This can be run in DrRacket:
Welcome to DrRacket, version 8.4 [cs].
Language: Beginning Student with List Abbreviations
The test passed!
>
The next steps in HtDF are template and inventory. For a function with one list
argument the "natural recursion" list template is likely to be appropriate;
(define (fn xs) ;; (Listof X) -> Y ; *template*
(cond ;
[(empty? xs) ... ] #|base case|# ;; Y ;
[else (... #|something|# ;; X Y -> Y ;
(first xs) (fn (rest xs))) ])) ;
With this template the function and the next tests become:
(define (sum-evens-with-prev xs) ;; (Listof Number) -> Number
;; produce total of each even x with its previous element (prev of first is 0)
(cond
[(empty? xs) 0 ] #|base case: from minimal example|#
[else (error "with arguments: " #|something: ?|#
(first xs) (sum-evens-with-prev (rest xs))) ]))
(check-expect (sum-evens-with-prev '(1)) 0)
(check-expect (sum-evens-with-prev '(2)) 2)
These tests fail, but the error messages and purpose statement suggest what is required:
the (... #|something|# from the template has to choose whether to add (first xs):
(define (sum-evens-with-prev xs) ;; (Listof Integer) -> Integer
;; produce total of each even x with its previous element (prev of first is 0)
(cond
[(empty? xs) 0 ]
[else
(if (even? (first xs))
(+ (first xs) (sum-evens-with-prev (rest xs)))
(sum-evens-with-prev (rest xs))) ]))
Now all 3 tests pass! Time for more check-expects (note: careful introduction of
check-expects is a way of clarifying ones understanding of the requirements, and
points one to the code to be added):
(check-expect (sum-evens-with-prev '(1 1)) 0)
(check-expect (sum-evens-with-prev '(1 2)) 3)
Ran 5 tests.
1 of the 5 tests failed.
Check failures:
Actual value 2 differs from 3, the expected value.
sum-evens-with-prev needs the prev value to include in the even? case:
make it available by introducing it as an argument (renaming the function), add
the appropriate arguments to the recursive calls, the function now just calls
sum-evens-and-prev:
(define (sum-evens-and-prev xs prev) ;; (Listof Integer) Integer -> Integer
;; produce total of each even x and prev
(cond
[(empty? xs) 0 ]
[else
(if (even? (first xs))
(+ prev (first xs) (sum-evens-and-prev (rest xs) (first xs)))
(sum-evens-and-prev (rest xs) (first xs))) ]))
(define (sum-evens-with-prev xs) ;; (Listof Integer) -> Integer
;; produce total of each even x with its previous element (prev of first is 0)
(sum-evens-and-prev xs 0))
(just add some more tests, and all is well :)
(check-expect (sum-evens-with-prev '(0 2)) 2)
(check-expect (sum-evens-with-prev '(2 1)) 2)
(check-expect (sum-evens-with-prev '(1 3)) 0)
(check-expect (sum-evens-with-prev '(2 2)) 6)
(check-expect (sum-evens-with-prev '(1 2 3 4)) 10)
(check-expect (sum-evens-with-prev '(1 2 3 3 5 6 6)) 26)
Welcome to DrRacket, version 8.4 [cs].
Language: Beginning Student with List Abbreviations.
All 11 tests passed!
>

The (for/fold) form requires a (values) clause, and it is in that which you would put the conditional form.
Assuming you want only the new list as the return value, you would also want a #:result clause following the iteration variables.
(define loopl
(lambda (l)
(for/fold
([index 0]
[acc '()]
#:result acc)
([i l])
(values [+ index 1]
[append acc
(if (and (> index 0)
(even? i))
(list (+ i (list-ref l (- index 1))))
(list i))]))))
This should give the correct answer.

You almost never want to repeatedly call list-ref in a loop: that makes for horrible performance. Remember that (list-ref l i) takes time proportional to i: in your case you're going to be calling list-ref with the index being, potentially 0, 1, ..., and that going to result in quadratic performance, which is bad.
Instead there's a neat trick if you want to iterate over elements of a list offset by a fixed amount (here 1): iterate over two lists: the list itself and its tail.
In addition you need to check that the first element of the list is not even (because there is no previous element in that case, so this is an error).
Finally I'm not entirely sure what you wanted to return from the function: I'm assuming it's the sum.
(define (accum-even-previouses l)
(unless (not (even? (first l)))
;; if the first elt is even this is an error
(error 'accum-even-previouses "even first elt"))
(for/fold ([accum 0])
([this (in-list (rest l))]
[previous (in-list l)])
(+ accum (if (even? this)
(+ this previous)
0))))

Related

how to make a recursive racket list that, from the input list, outputs its decreasing to 1 for every element in the list (e.g. ('3 2) outputs ('32121)

****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)

Lisp Function that Returns a Sum

I am trying to write a weird function, so bear with me here. This function should take a list L as a parameter and have a sum variable. If L is not a list, it should return nil. Otherwise, it should iterate through each element of the list and do the following:
If the element is a number and less than zero, it should subtract 1 from the sum.
If the element is a number and greater than zero, it should add 1 to the sum.
if the element is 0 or not a number, then it should add 0 to the sum.
Here's the code I have, but it returns 0 regardless of arguments passed in:
(defun sigsum (L)
(let ((sum 0)) ;;variable sum
(if (not (listp L)) ;;if L is not a list
nil ;;return nil
(dotimes (i (length L)) ;;otherwise loop through L
(if (numberp (elt L i)) ;;if each element is a number
(if (< (elt L i) 0) ;;if is less than 0 subtract 1 from sum
(- sum 1)
(if (> (elt L i) 0) ;;if greater than 0 add 1 to sum
(+ sum 1))
(+ sum 0)) ;;else add 0 to sum
(+ sum 0))) ;;not a number so add 0 to sum
)
sum) ;;return sum
)
As always, any help is greatly appreciated.
Other answers have described the problems in your code, but it might be beneficial to look at other ways of solving the problem. This is a pretty typical case for a reduction with a key function (see reduce). You can sum up the elements in list with (reduce '+ list). However, you don't want to just sum up the elements, some of which might not be numbers, you want to map each element to a number (-1, 0, or 1), and add those up. That means you need a key function. First, let's define the function that takes an element to either -1, 0, or 1:
(defun to-number (x)
(cond
((and (numberp x) (< x 0)) -1)
((and (numberp x) (> x 0)) 1)
((or (not (numberp x)) (zerop x)) 0)))
Then your sum function needs to return nil if its argument is not a list, or (reduce '+ … :key 'to-number) if its argument is a list:
(defun sum (thing)
(if (not (listp thing))
nil
(reduce '+ thing :key 'to-number)))
Conceptually, this approach is the same as applying the addition operator to the result of (mapcar 'to-number list), but reduce is generally preferred, because there can be a maximum number of arguments a function can be called with, so (apply '+ (mapcar …)) breaks if (mapcar …) returns a list that's longer than that. The other problem is that mapcar will allocate a whole new list to hold the intermediate values (the results of to-number), which is an unnecessary space usage.
(- sum 1) does not update any variables. Since you don't use the result it goes away. It's like this is all programming languages. sum + 1 in an Algol language (like C) does not update sum.
If you want to update a variable you can use setf:
(setf sum (+ sum 1))
(setf sum (- sum 1))
Or you can use incf and decf that are macroes that expand to the same as the above expressions.
There are many other ways you can do it in CL. You can use reduce
(defun mysignum (list)
(if (listp list)
(reduce (lambda (e acc)
(+ acc
(cond ((or (not (numberp e)) (zerop e)) 0)
((< e 0) -1)
(t 1))))
list)
nil))
You can use loop:
(defun mysignum (list)
(if (listp list)
(loop :for e :in list
:when (and (numberp e) (< e 0))
:summing -1
:end
:when (and (numberp e) (> e 0))
:summing +1
:end)
nil))
The expression (+ sum 1) returns one more than sum. It does not change sum. You can get where you want using incf or decf, which modify places.
You could also use loop:
(loop :for element :in list
:count (and (numberp element) (plusp element)) :into plus
:count (and (numberp element) (minusp element)) :into minus
:finally (return (- plus minus)))
Signum is also useful, but it has float contagion (if any of the numbers are floats, the result will be a float as well).
(loop :for element :in list
:when (numberp element)
:sum (signum element))
(defun discrete (lis)
(cond
((and (listp lis) (not (equal lis nil)))
(let ((sum 0))
(loop for item in lis do
(cond ((or (not (numberp item)) (equal 0 item)) t)
((and (numberp item) (> item 1)) (setf sum (+ 1 sum)))
((and (numberp item) (< item 1)) (setf sum (- sum 1)))))
sum))))
Usage:(discrete '(-1 2 3 0 2 2 -1 2 34 0 -1))=> 3
(discrete '(-4 a b))=> -1
(discrete '()) => NIL
(discrete '(a s d f))=> 0

Scheme: Printing out first n elements of list

First off, scheme: return a lst that only contains the first element of the lst did not help much, as the question was never really answered, and I followed the contributor's suggestions to no success. Furthermore, I am approaching this with a do loop, and have almost achieved the solution.
I need to make a procedure that will return the first n items in a passed list. For example, (first-n 4 '(5 8 2 9 4 0 8 7)) should give (5 8 2 9).
Here is my approach, the display is there to make sure that the loop is working, which it is:
(define (front-n n list)
(do ((i 0 (+ i 1)))
((> i (- n 1)))
(display (list-ref list i))))
How do I go about making that return a list, or output a list?
Your do-loop, and #Penguino's recursive function, both fail if there are less than n items in the input list. Here is a simple version based on named-let, renamed take which is the normal name for this function:
(define (take n xs)
(let loop ((n n) (xs xs) (zs (list)))
(if (or (zero? n) (null? xs))
(reverse zs)
(loop (- n 1) (cdr xs)
(cons (car xs) zs)))))
Or, if you prefer the recursive function version:
(define (take n xs)
(if (or (zero? n) (null? xs))
(list)
(cons (car xs) (take (- n 1) (cdr xs)))))
The named-let version is preferable to the recursive version, because the recursion isn't in tail position, so it builds a large intermediate stack.
You said that you wanted a version using do. That's harder, because the test that terminates the loop is performed after the action of the loop, and you need to perform the test before the action. You can either test one-ahead, which is awkward, or use this loop that delays the action until after the test has succeeded:
(define (take n xs)
(let ((zs (list)))
(do ((n n (- n 1)) (xs xs (cdr xs)))
((or (zero? n) (null? xs)) (reverse zs))
(set! zs (cons (car xs) zs)))))
The set! isn't particularly Schemely, but at least it shares with the named-let version the property that it doesn't build an intermediate stack.
How about
(define (front-n n list)
(cond ((= 0 n) '())
(else (cons (car list) (front-n (- n 1) (cdr list))))))
with a little pseudo-error-trapping added.
Testing with:
(front-n 4 '(5 8 2 9 4 0 8 7))
(front-n 8 '(5 8 2 9 4 0 8 7))
produces the expected output:
'(5 8 2 9)
'(5 8 2 9 4 0 8 7)
>
Note that the error checking may be useful.
Here is a tail recursive version:
(define (take n a-list)
(define (iter counter result sublist)
(cond
[(empty? sublist) result]
[(< counter n)
(iter
(+ counter 1)
(append result (list (car sublist)))
(cdr sublist))]
[else result]))
(cond
[(= n 0) '()]
[else (iter 0 '() a-list)]))
It differs slightly from the library procedure, because the library procedure throws an error, if you give a take count which is larger than the length of the list, while this function returns the whole list in that case.
Note however, that it makes use of append. I could not figure out a way around that yet.

How to return a list of numbers between 1 and x

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))))

How do I handle a variable number of arguments passed to a function in Racket?

I like creating functions which take an unlimited number of arguments, and being able to deal with them as a list. It's been useful to me when creating binary trees & I'm using it for a variation on the nearest-neighbor algorithm right now. My method, however, is really horrible: since I can't think of a way to iterate over an improper list (which may well be improper & degenerate), I tried using various list functions to force the improper list into list form.
This is my best attempt in a simple function to determine difference between map-nodes (works, just not sure why it works):
(define distance-between
(lambda xs
(let ([input-list (list* xs null)])
(letrec
([f (lambda (xs acc)
(if (null? (cdr xs))
acc
(f (cdr xs)
(+ (abs (- (map-node-x (car xs))
(map-node-x (cadr xs))))
(abs (- (map-node-y (car xs))
(map-node-y (cadr xs))))
acc))))])
(f (car input-list) 0)))))
As you can see, it's an ugly solution and involves some of what seems like magic to me - why is the improper list coerced into list form when I include it in a list*? (note: this sentence is misleading, this does not occur).
I'd rather have a pretty solution and no magic. Can anyone help?
For example a typical input would be:
(distance-between (map-node 1 2) (map-node 2 3) (map-node 3 4))
with the expected result:
4
(a distance of 2 between map-node (a) and m-n (b), plus a distance of 2 between map-node (b) and map-node (c)).
Alternatively one might simply input:
(distance-between (map-node 1 2) (map-node 2 2))
and get an answer of:
1
If I attempted this on the raw input, without my (let ([input-list...])...) statement, it would cause an error as (? not actually sure why given response to this question).
The function works as expected.
There's nothing improper about the list received as a variadic argument list (meaning: variable number of arguments). For example:
(define test-list
(lambda xs
(length xs))) ; xs is a normal list, use it like any other list
(test-list 1 2 3 4)
=> 4
In the above example, the xs parameter is a normal, plain, vanilla list, there's nothing improper about it. You can iterate over it as you would over any other list. There's no need to car it, it's already a list! Also, notice that the same function can be written like this:
(define (test-list . xs)
(length xs)) ; xs is a normal list, use it like any other list
Just for reference: an improper list is one that does not end with the null list. For example: '(1 2 3 . 4). Again, that's not how a variadic argument list looks.
I also don't understand how your variadic argument list could be improper.
But to answer your original question (how to iterate over a possibly improper list, somewhat more elegantly), here is one way using match:
#lang racket
(define (properly-sum-improper-list xs)
(let loop ([acc 0]
[xs xs])
(match xs
[(list) acc]
[(cons x more) (loop (+ acc x) more)]
[x (+ acc x)]))) ;last item of improper list
(require rackunit)
(check-equal? (properly-sum-improper-list '(1 2 3 4)) 10)
(check-equal? (properly-sum-improper-list '(1 2 3 . 4)) 10)
However needing to do this, at all, is probably an indication you want to fix or change something else.
Your list is not improper. When your argument is not a pair, like (lambda xs body ...) or (define (fun . xs) body ...) all your arguments gets slurped into a list. Eg.. (fun 1 2 3) would make xs '(1 2 3). Doing (list* '(1 2 3) '()) makes '((1 2 3) which you undo right away by calling your loop with car which makes it '(1 2 3) again.
Other than that your procedure works as intended. You might clean up your procedure a little, but since there is no list comprehensions that glides over a list folding over the two next elements it won't become much smaller. Below is basically the same code, but abstracting out the procedure that does the work (which if existed a foldl-pair you could have used) and with a named let as a iterator loop (which is syntactic sugar for a letrec+call).
(define (distance-between e1 . lst)
(define (add-diff-acc e1 e2 acc)
(+ (abs (- (map-node-x e1) (map-node-x e2)))
(abs (- (map-node-y e1) (map-node-y e2)))
acc))
(let iterate ((e1 e1) (lst lst) (acc 0))
(if (pair? lst)
(let ((e2 (car lst)))
(iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
acc)))
EDIT: About syntax sugar, named let and letrec.
(let ((x 10) (y 19))
body)
is syntactic sugar for a anonymous procedure call
((lambda (x y)
body)
10 19)
A named let is just giving that procedure a name, though as if by letrec, making a recursive binding. you call it with the name you give and the arguments will be what you supply instead of the initial value in the let. I'm used to them and prefer them today. It might take some time to get used to though.
Most of the code we write is syntactic sugar for some lower level stuff. The macros are nested so that your letrec form could get reduced down lambdas eventually. The whole procedure without syntactic sugar would look like this:
(define distance-between
(lambda (e1 . lst)
((lambda (add-diff-acc)
((lambda (iterate e1 lst acc) ; emulate Y to substitute `letrec`
(iterate iterate e1 lst acc))
(lambda (iterate e1 lst acc)
(if (pair? lst)
((lambda (e2)
(iterate iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
(car lst))
acc))
e1 lst 0))
(lambda (e1 e2 acc)
(+ (abs (- (map-node-x e1) (map-node-x e2)))
(abs (- (map-node-y e1) (map-node-y e2)))
acc)))))