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
Related
I'm trying to get a list with the average of the following n elements. I'm reading a csv file that has 7 columns im just using the 6th one that has number values in order to get the average.
This is the code
;Function that returns a list containing the values of the desired column
(define (get-column col)
(let loop
([file (cdr(all-rows csv-path read-csv))]
[result empty])
(if (empty? file)
result
(loop (cdr file)
(cond
[(equal? col 1) (append result (list (caar file)))]
[(equal? col 2) (append result (list (string->number(cadar file))))]
[(equal? col 3) (append result (list (string->number(caddar file))))]
[(equal? col 4) (append result (list (string->number(car (cdddar file)))))]
[(equal? col 5) (append result (list (string->number(cadr (cdddar file)))))]
[(equal? col 6) (append result (list (string->number(caddr (cdddar file)))))]
[(equal? col 7) (append result (list (string->number(car (cdddr (cdddar file))))))]
)))))
(define (suma-SMA col n)
(let loop
([n n]
[res 0]
[col col])
(if (zero? n)
res
(loop (sub1 n) (+ res (car col)) (cdr col)))))
(define (get-SMA days)
(let loop
([col (get-column 6)]
[result empty])
(if (empty? col)
result
(loop (cdr col)(append result (list (suma-SMA col days)))))))
Here's a function that does what you asked for in the comments, e.g. given (1 2 3 4) it produces ((1+2)/2 (2+3)/2 (3+4)/2).
(define (sum list)
(cond
((null? list)
'()) ;; error?
((null? (cdr list))
'())
(else
(cons (/ (+ (car list) (cadr list)) 2) (sum (cdr list))))))
I'm still a bit confused because even the combination of get-SMA and suma-SMA does nothing like this. It's completely unclear what the days variable is doing, as you can see I didn't need it in my code above.
So I may have misunderstood what you are trying to do, but the function above does what you actually asked for so hopefully it will be helpful.
Here is the answer that I found useful for my problem.
(define (sum list n)
(cond
((null? list)
'()) ;; error?
((null? (cdr list))
'())
(else
(cons (suma-SMA list n) (sum (cdr list) n)))))
Newbie question in Common Lisp:
How to make my procedure to return distinct procedural object with its own local binding each time call? Currently, I use let to create the local state, but two function calls are sharing the same local state. Here is the code,
(defun make-acc ()
(let ((balance 100))
(defun withdraw (amount)
(setf balance (- balance amount))
(print balance))
(defun deposit (amount)
(setf balance (+ balance amount))
(print balance))
(lambda (m)
(cond ((equal m 'withdraw)
(lambda (x) (withdraw x)))
((equal m 'deposit)
(lambda (x) (deposit x)))))))
;; test
(setf peter-acc (make-acc))
(setf paul-acc (make-acc))
(funcall (funcall peter-acc 'withdraw) 10)
;; Give 90
(funcall (funcall paul-acc 'withdraw) 10)
;; Expect 90 but give 80
Should I do it in another way? Is my way of writing wrong? Can someone pls help me to clear this doubt? Thanks in advance.
Note that, even after the defun-is-global problem is dealt with, you need far less machinery than you have to do something like this. For instance:
(defun make-account (balance)
(lambda (op amount)
(ecase op
((withdraw)
(decf balance amount))
((deposit)
(incf balance amount)))))
(defun account-operation (account op &rest args-to-op)
(apply account op args-to-op))
Then
> (setf joe-acct (make-account 10))
#<Closure 1 subfunction of make-account 4060010B54>
> (setf mary-acct (make-account 100))
#<Closure 1 subfunction of make-account 4060010C94>
> (account-operation joe-acct 'withdraw 10)
0
> (account-operation mary-acct 'deposit 10)
110
Obviously account-operation is just a convenience.
Maybe you want object orientation?
(defclass account ()
((balance :initarg :balance
:initform 100
:accessor balance)))
(defmethod withdraw ((acc account) amount)
(decf (balance acc) amount))
(defmethod deposit ((acc account) amount)
(incf (balance acc) amount))
Usage:
(defparameter alice-account (make-instance 'account))
(withdraw alice-account 25) ;; => 75
(balance alice-account) ;; => 75
We can create accounts with another balance:
(defparameter bob-account (make-instance 'account :balance 90))
For more, I suggest the Cookbook: https://lispcookbook.github.io/cl-cookbook/clos.html
A general rule is that defun should be used only when defining a function at top level. To define local functions the two special operators flet and labels can be used (manual).
For instance:
(defun make-acc ()
(let ((balance 100))
(flet ((withdraw (amount)
(setf balance (- balance amount))
(print balance))
(deposit (amount)
(setf balance (+ balance amount))
(print balance)))
(lambda (m)
(cond ((equal m 'withdraw)
(lambda (x) (withdraw x)))
((equal m 'deposit)
(lambda (x) (deposit x))))))))
labels is like flet, but it is used when there are recursive definitions.
Then you don't need to return functions inside the function returned by make-acc, but in it you can simply execute the required operation:
(defun make-acc ()
(let ((balance 100))
(flet ((withdraw (amount)
(setf balance (- balance amount))
(print balance))
(deposit (amount)
(setf balance (+ balance amount))
(print balance)))
(lambda (m x)
(cond ((equal m 'withdraw)
(withdraw x))
((equal m 'deposit)
(deposit x)))))))
The call will be more simple and will return the expected value:
CL-USER> (setf paul-acc (make-acc))
#<CCL:COMPILED-LEXICAL-CLOSURE (:INTERNAL MAKE-ACC) #x3020021640AF>
CL-USER> (funcall paul-acc 'withdraw 10)
90
90
CL-USER> (funcall paul-acc 'withdraw 10)
80
80
Finally, if you want you can also return two different functions to perform deposit and withdrawal on the account:
(defun make-acc (initial-amount)
(let ((balance initial-amount))
(flet ((withdraw (amount)
(setf balance (- balance amount))
(print balance))
(deposit (amount)
(setf balance (+ balance amount))
(print balance)))
(values #'withdraw #'deposit))))
using this for instance as:
(multiple-value-bind (paul-withdraw paul-deposit)
(make-acc 100)
(funcall paul-withdraw 10)
(funcall paul-withdraw 10))
The only serious problem here is defun that in common lisp is not used to define local functions.
You could for example use lambdas for those operations, especially as you want to return lambdas...
(defun make-acc ()
(let* ((balance 100)
(withdraw (lambda (amount)
(setf balance (- balance amount))
(print balance)))
(deposit (lambda (amount)
(setf balance (+ balance amount))
(print balance))))
(lambda (m)
(cond
((equal m 'withdraw) withdraw)
((equal m 'deposit) deposit)))))
Note that I used let* instead of let because you need to be able to see balance in the two following bindings.
This program is forbidden to use any kinds of list. I tried the following method but it is crazy.
(define (order2 number2)
(cond ((remainder number2 10) 1)
(else (order3 number3))))
(define (order3 number3)
(cond ((< number3 10) number3)
(else
(define (order4 number4)
(cond (< remainder (quotient number4 10)))
(else (order4 (quotient number4)))))))
))
I have a series of expressions to convert from postfix to prefix and I thought that I would try to write a program to do it for me in DrRacket. I am getting stuck with some of the more complex ones such as (10 (1 2 3 +) ^).
I have the very simple case down for (1 2 \*) → (\* 1 2). I have set these expressions up as a list and I know that you have to use cdr/car and recursion to do it but that is where I get stuck.
My inputs will be something along the lines of '(1 2 +).
I have for simple things such as '(1 2 +):
(define ans '())
(define (post-pre lst)
(set! ans (list (last lst) (first lst) (second lst))))
For the more complex stuff I have this (which fails to work correctly):
(define ans '())
(define (post-pre-comp lst)
(cond [(pair? (car lst)) (post-pre-comp (car lst))]
[(pair? (cdr lst)) (post-pre-comp (cdr lst))]
[else (set! ans (list (last lst) (first lst) (second lst)))]))
Obviously I am getting tripped up because (cdr lst) will return a pair most of the time. I'm guessing my structure of the else statement is wrong and I need it to be cons instead of list, but I'm not sure how to get that to work properly in this case.
Were you thinking of something like this?
(define (pp sxp)
(cond
((null? sxp) sxp)
((list? sxp) (let-values (((args op) (split-at-right sxp 1)))
(cons (car op) (map pp args))))
(else sxp)))
then
> (pp '(1 2 *))
'(* 1 2)
> (pp '(10 (1 2 3 +) ^))
'(^ 10 (+ 1 2 3))
Try something like this:
(define (postfix->prefix expr)
(cond
[(and (list? expr) (not (null? expr)))
(define op (last expr))
(define args (drop-right expr 1))
(cons op (map postfix->prefix args))]
[else expr]))
This operates on the structure recursively by using map to call itself on the arguments to each call.
(define length1
(lambda (lat)
(cond
((null? lat) 0)
(else (+ 1 (length1 (cdr lat)))))))
for example: display the number (or anything else) when call length1 in cond
for common lisp you can use (progn (...) (...) ...) to group together multiple expressions into one.
the equivalent in scheme is (begin (...) (...) ...).
so:
(define length1
(lambda (lat)
(cond
((null? lat) 0)
(else (begin (display "hello world") (+ 1 (length1 (cdr lat))))))))
or maybe you want:
(define length1
(lambda (lat)
(cond
((null? lat) 0)
(else (let ((or-anything-else (+ 1 (length1 (cdr lat)))))
(display or-anything-else)
or-anything-else)))
and that's about exhausted my patience.