# Exam Prep 9: Macros examprep09.pdf

Students from past semesters wanted more content and structured time to prepare for exams. Exam Prep sections are a way to solidify your understanding of the week's materials. The problems are typically designed to be a bridge between discussion/lab/homework difficulty and exam difficulty.

Reminder: There is nothing to turn in and there is no credit given for attending Exam Prep Sections.

We try to make these problems exam level , so you are not expected to be able to solve them coming straight from lecture without additional practice. To get the most out of Exam Prep, we recommend you try these problems first on your own before coming to the Exam Prep section, where we will explain how to solve these problems while giving tips and advice for the exam. Do not worry if you struggle with these problems, it is okay to struggle while learning.

You can work with anyone you want, including sharing solutions. We just ask you don't spoil the problems for anyone else in the class. Thanks!

You may only put code where there are underscores for the codewriting questions.

You can test your functions on their doctests by clicking the red test tube in the top right corner after clicking Run in 61A Code. Passing the doctests is not necessarily enough to get the problem fully correct. You must fully solve the stated problem.

### Q1: Arg Repeater

Difficulty: ⭐

First, write the procedure `repeater`, which takes in expression `expr` and a non-negative integer `k`, and outputs a new list with `expr` repeated `k` times.

Then write the macro `arg-repeater`, which takes in a function `fn`, an expression `expr` and a non-negative integer `k`, which corresponds to the number of arguments that `fn` takes in. `arg-repeater` passes `k` copies of `expr` to a call to `fn`.

Note: The skeleton code is just a suggestion; feel free to use your own structure if you prefer.

Run in 61A Code
Solution
``````(define (repeater expr k)
; Returns a list with k copies of expr
(if (= 0 k)      nil      (cons expr (repeater expr (- k 1)))))
(expect (repeater 2 0) ())
(expect (repeater 2 5) (2 2 2 2 2))

(define-macro (arg-repeater fn expr k)
; Fills in fn with k copies of expr
(cons fn (repeater expr k)))
(define (add-four a b c d) (+ a b c d))
(define (mult-one x) x)
(define (mult-seven a1 a2 a3 a4 a5 a6 a7)
(* a1 a2 a3 a4 a5 a6 a7))

(expect (arg-repeater add-four 10 4) 40)
(expect (arg-repeater mult-one -2 1) -2)
; 2 multiplied to itself 7 times = 2^7 = 128
(expect (arg-repeater mult-seven 2 7) 128)``````

### Q2: Replace

Difficulty: ⭐⭐

Write the macro `replace`, which takes in a Scheme expression `expr`, a Scheme symbol or number `old`, and a Scheme expression `new`. The macro replaces all instances of `old` with `new` before running the modified code.

Also, fill in `repeat-nested` to be a function which takes in a Scheme value `x` and a non-negative integer `n` and returns a list with `n` copies of `x`.

Note: The skeleton code is just a suggestion; feel free to use your own structure if you prefer.

Run in 61A Code
Solution
``````(define (replace-helper e o n)
(if (pair? e)      (cons (replace-helper (car e) o n) (replace-helper (cdr e) o n))      (if (eq? e o) n e)))(define-macro (replace expr old new)
(replace-helper expr old new))

(replace (define (repeat-nested x n) (if (= n 0) nil (cons x (repeat-nested x (- n 1))))) cons list)(replace (define x 3) 3 5)

(define nested (replace (cons 1 (cons 2 (cons 3 (cons 4 nil)))) cons list))

(expect x 5)
(expect nested (1 (2 (3 (4 ())))))
(expect (repeat-nested 5 3) (5 (5 (5 ()))))``````

### Q3: K-Curry

Difficulty: ⭐

First, write the procedure `remove`, which takes in a list `lst` and a sorted list of non-negative indices `idxs`, outputting a new list with all of the elements at indices within `idxs` removed. In other words, `remove` will remove values from the `idxs` positions and return whatever remains. You may assume that all calls to `remove` pass in compatible values for `lst` and `idxs`.

Next, write the procedure `splice`, which takes in a list `args`, a sorted list of non-negative indices `indices` and a list `vals`. The `indices` and `vals` list must be the same length. The procedure outputs a new list identical to `args`, except the values of `vals` are substituted in at the indices specified by `indices`. Once again, you may assume all arguments are compatible and do not have to handle errors.

With these two helper functions, write the macro `k-curry`, which takes in a function `fn`, a list of the function's arguments `args`, a list of `k` values to substitute in for these arguments, and a sorted list of `k` non-negative indices specifying which arguments to pass values from `vals` into. `k-curry` will return a new function which takes in whatever arguments are remaining from `fn`'s list of arguments, with the arguments picked out by `indices` automatically filled in with the values from `vals`.

Note: The skeleton code is just a suggestion; feel free to use your own structure if you prefer.

Run in 61A Code
Solution
``````(define (remove lst idxs)
; return items of list that aren't at idxs
(cond
((null? lst) nil)    ((and (not (null? idxs)) (= 0 (car idxs)))
(= 0 (car idxs))
(remove (cdr lst) (map decrease (cdr idxs))))    (else
(cons (car lst) (remove (cdr lst) (map decrease idxs))))))
(expect (remove '(10 9 8 7 6 5 4) '(0 2 3)) (9 6 5 4))
(expect (remove '(10 9 8 7 6 5 4) '()) (10 9 8 7 6 5 4))

; Q3

(define (splice args indices vals)
(cond
((null? args) nil)    ((and (not (null? indices)) (= 0 (car indices)))     (cons (car vals)
(splice (cdr args) (map decrease (cdr indices)) (cdr vals))))    (else
(cons (car args)
(splice (cdr args) (map decrease indices) vals)))))
(expect (splice '(10 9 8 7 6 5 4) '(0 2 3) '(a b c)) (a 9 b c 6 5 4))

(define-macro (k-curry fn args vals indices)
(let ((args-left (remove args indices))
(spliced-args (splice args indices vals)))
`(lambda ,args-left (,fn ,@spliced-args))))
(define (f a b c d) (- (+ a c) (+ b d)))
(define minus-six (k-curry f (a b c d) (2 4) (1 3)))

; (10 + 8) - 6
(expect (minus-six 8 10) 12)``````