I want to loop this one until the nr-of-bread is 2 how to do it?
(when (and (>= money price-of-bread) (< nr-of-bread 2))
(set! nr-of-bread (+ nr-of-bread 1)) (set! money (- money price-of-bread)))
The best way to achieve that is using tail recursion via named let:
(let loop ((nr-of-bread 0)
(rest money))
(if (and (>= rest price-of-bread) (< nr-of-bread 2))
(loop (add1 nr-of-bread) (- rest price-of-bread))
nr-of-bread))
Related
I am trying to understand Racket's macros. For that, I built this function for a specific purpose:
(define (while-less-fun max)
(cond [(< a (- max 1))
(and (begin (set! a (+ a 1)) (print "x") a) (while-less-fun max))]
[(< a max)
(begin (set! a (+ a 1)) (print "x") a)]
[(>= a max)
(begin (set! a (+ a 1)) (print "x") a)]
))
It works as intended on the REPL:
> a
2
> (while-less-fun 7)
"x""x""x""x""x"7
> a
7
I tried to transform the function above in the macro bellow. My goal would be to generate the same results:
(define-syntax while-less
(syntax-rules (do)
[(while-less maximo do begin-exp)
(cond [(< a (- maximo 1))
(and begin-exp (while-less maximo do begin-exp))]
[(< a maximo)
begin-exp]
[(>= a maximo)
begin-exp])]))
The expected result was:
(define a 2)
(while-less 7 do (begin (set! a (+ a 1)) (print "x") a))
(while-less 7 do (begin (set! a (+ a 1)) (print "x") a))
Evaluating the second line would print "x" 5 times and change a to be 7. Also, evaluating the third line would print "x" 1 time and would change a to be 8.
Unfortunately, this generates an infinite recursion which really surprises me.
What did I do wrong? Why did this infinite recursion happen?
I know that you should avoid writing macros when a function is able to solve the problem. But, is my approach the wrong way of trying to accomplish this task?
In the first cond clause, you call "(while-less maximo do begin-exp)" with the same arguments, the entire body of the macro will be expanded again by calling the same "(while-less maximo do begin-exp)", causing the loop.
What you can do is create a generic while for a condition:
(define-syntax while
(syntax-rules (do)
[(while condition do begin-exp)
(let loop ()
(when condition
begin-exp
(loop)))]))
> (define a 2)
> (while (< a 7) do (begin (set! a (+ a 1)) (print "x") a))
"x""x""x""x""x"
> (while (< a 7) do (begin (set! a (+ a 1)) (print "x") a))
>
Use accumulative recursion to write a function called update-balance that consumes a list of transactions, lot, a starting balance at the beginning of the month (considered day 0), start-bal, and a non-‐negative number representing a minimum balance, min-bal. The function produces the balance of a bank account after completing all of the transactions in lot.
Having a problem with use of accumulative recursion
(define (trans-val t start-bal min-bal)
(cond
[(symbol=? (trans-action t) 'withdraw)
(cond
[(>= (- start-bal (trans-amt t)) min-bal)
(- start-bal (trans-amt t))]
[else (- start-bal (+ 1 (trans-amt t)))])]
[else
(cond
[(>= (+ start-bal (trans-amt t)) min-bal)
(+ start-bal (trans-amt t))]
[else (+ start-bal (- (trans-amt t) 1))])]))
Maybe something like this?
(define (update-balance lot start-bal min-bal)
(if (null? lot)
; no more transactions to process -> return start-bal
start-bal
; take next transaction (t), calculate new balance
(let* ((t (car lot))
(new-bal ((if (eq? (trans-action t) 'withdraw) - +)
start-bal
(trans-amt t))))
; if new balance >= minimum balance, use that, otherwise retain previous balance
; in any case, tail-recursively call update-balance to process the next transaction
(update-balance (cdr lot)
(if (>= new-bal min-bal) new-bal start-bal)
min-bal))))
Testing:
> (update-balance (list (trans 'deposit 100) (trans 'withdraw 80)) 0 0)
20
> (update-balance (list (trans 'deposit 10) (trans 'withdraw 80)) 0 0)
10
Given a list, and a number, n, I am trying to split a list into two separate lists: one into a list of length n, and the second list being the rest of the original list.
Here is what I have:
(define (part lst i)
(if (> i 0)
(list (append (list (first lst)) (list (part (rest lst) (- i 1)))))
(append lst)))
Where lst is the inputted list, and i is the number. When I input the list '(1 2 3 4) with the number 2, I return an output of: '((1 ((2 (3 4))))) instead of what I want which is '((1 2) (3 4)).
This is for a homework assignment, so it would be much appreciated if someone could just point me in the right direction as to where my problem lies, and because it is a hw assignment, I only am allowed to use the simple racket functions.
EDIT:
When I change the code to:
(define (part lst i)
(if (> i 0)
(append (list (first lst)) (list (part (rest lst) (- i 1))))
(append lst)))
I get an output of '(1 (2 (3 4))).
Using existing libraries
There's an easy way to solve this problem in Racket, just use the built-in split-at procedure (also available in the SRFI-1 library). This has the advantage of making a single pass across the input list:
(define (part lst i)
(let-values (((head tail) (split-at lst i)))
(list head tail)))
Another option would be to use Racket's built-in procedures take and drop (also available in SRFI-1) - but this will make two passes across the input list:
(define (part lst i)
(list (take lst i)
(drop lst i)))
Implementation from scratch
To build our own solution, we could write a procedure that makes a single pass, like this:
(define (part lst i)
(if (negative? i)
(error "index can't be negative")
(let loop ((lst lst) (acc '()) (i i))
(cond ((and (empty? lst) (positive? i))
(error "index is too large for list"))
((zero? i)
(list (reverse acc) lst))
(else
(loop (rest lst) (cons (first lst) acc) (sub1 i)))))))
Also, we could implement our own versions of take and drop - again, this will traverse the input list twice:
(define (my-take lst i)
(if (> i 0)
(cons (first lst)
(my-take (rest lst) (- i 1)))
'()))
(define (my-drop lst i)
(if (> i 0)
(my-drop (rest lst) (- i 1))
lst))
(define (part lst i)
(list (my-take lst i)
(my-drop lst i)))
How would I recurse through nested lists?
For example, given: '((A 1 2) (B 3 4))
How would I add 2 to the second element in each nested sublist?
(defun get-p0 (points)
(loop for x from 0 to
(- (list-length points) 1) do
(+ 2 (cadr (nth x points)))
)
)
I'm not really sure why (get-p0 '((A 1 2) (B 3 4))) returns NIL.
I'd go with something like this:
(loop for (letter x y) in '((A 1 2) (B 3 4))
collect (list letter (+ 2 x) y))
The reason: it's shorter and you don't measure the length of the list in order to iterate over it (why would you do that?)
Since you ask for a recursive solution:
(defun get-p0 (lst &optional (n 0))
(if (null lst)
nil
(let ((elt1 (first lst)) (eltn (cdr lst)))
(if (listp elt1)
(cons (get-p0 elt1) (get-p0 eltn))
(cons (if (= n 1) (+ elt1 2) elt1) (get-p0 eltn (+ n 1)))))))
so
? (get-p0 '((A 1 2) (B 3 4)))
((A 3 2) (B 5 4))
and it recurses further down if necessary:
? (get-p0 '((A 0 2) ((B -4 4) (C 10 4))))
((A 2 2) ((B -2 4) (C 12 4)))
The way you put it, you can consider the problem as a basic recursion pattern: you go through a list using recursion or iteration (mapcar, reduce, etc.; dolist, loop, etc.) and apply a function to its entries. Here is a functional solution:
(defun get-p0 (points)
(mapcar #'add-2 points))
where the auxiliary function can be defined as follows:
(defun add-2 (lst)
"Add 2 to the 2nd item"
(let ((res '()))
(do ((l lst (cdr l))
(i 1 (1+ i)))
((null l) (nreverse res))
(push (if (= 2 i)
(+ 2 (car l))
(car l))
res))))
As written your 'loop' use does not return anything; thus NIL is returned. As is your code is simply iterating over x and computing something; that something isn't stored anywhere.
So, how to get your desired result? Assuming you are willing to modify each point in points, this should work:
(defun get-p0 (points)
(loop for x from 0 to (- (list-length points) 1) do
(let ((point (nth x points)))
(setf (cadr point) (+ 2 (cadr point)))))
points)
(defun merge-matrix (matrix-1 matrix-2)
(if (not (or (eql (matrix-rows matrix-1) (matrix-rows matrix-2)) (null matrix-1) (null matrix-2))) (error "Invalid dimensions."))
(cond
((null matrix-1) (copy-tree matrix-2))
((null matrix-2) (copy-tree matrix-1))
(t (let ((result (copy-tree matrix-1)))
(dotimes (i (matrix-rows matrix-1))
(setf (nth i result) (nconc (nth i result) (nth i matrix-2))))
result))))
(merge-matrix '((3 1) (1 3)) '((4 2) (1 1)))
*** - EVAL: variable NULL has no value
I receive an error like that how I can fix the problem, thanks
The OP's code works for me. However I felt motivated to improve it and
I implemented the same idea (but a bit more powerful).
The semantics are the same as Matlab's vertcat.
The function appends all arguments into one big matrix.
Note that due to the declarations my code should be super efficient.
(deftype mat ()
"Non-square matrices. Last index is columns, i.e. row-major order."
`(simple-array single-float 2))
(defun are-all-elements-typep (type ls)
(reduce #'(lambda (b x) (and b (typep x type)))
ls))
(defun are-all-matrix-heights-equalp (ls)
(let ((first-height (array-dimension (first ls) 0)))
(reduce #'(lambda (b x) (and b
(= first-height
(array-dimension x 0))))
ls)))
(defun vertcat (&rest rest)
(declare (type cons rest))
(unless (are-all-elements-typep 'mat rest)
(break "At least one of the arguments isn't a matrix."))
(unless (are-all-matrix-heights-equalp rest)
(break "All Matrices must have the same number of rows."))
(let* ((height (array-dimension (first rest) 0))
(widths (mapcar #'(lambda (mat) (array-dimension mat 1)) rest))
(result (make-array (list height
(reduce #'+ widths))
:element-type 'single-float))
(current-width 0))
(dotimes (m (length rest))
(let ((e (elt rest m)))
(destructuring-bind (y x) (array-dimensions e)
(dotimes (j y)
(dotimes (i x)
(setf (aref result j (+ current-width i))
(aref e j i))))
(incf current-width (elt widths m)))))
(the mat result)))
#+nil
(let ((a (make-array '(2 3)
:initial-contents '((1s0 2s0 3s0)
(2s0 4s0 5s0))
:element-type 'single-float))
(b (make-array '(2 2)
:initial-contents '((6s0 7s0)
(9s0 8s0))
:element-type 'single-float)))
(vertcat a b a))
;=> #2A ((1.0 2.0 3.0 6.0 7.0 1.0 2.0 3.0) (2.0 4.0 5.0 9.0 8.0 2.0 4.0 5.0))
The error message you're getting suggests that lisp is trying to treat one of your calls to null as a variable. I was able to replicate this behavior by defining matrix-rows like Frank Shearar did and deleting the parentheses around the ((null matrix-1) (copy-tree matrix-2)) s-expression, for example. I'd suggest you check your parentheses, either manually or using something like SLIME, which gave me a warning when I tried to compile the function.