Lisp: labels or separate global functions? - common-lisp

This is what my wason-deck produces:
((15 . D) (35 . H) (3 . B) (19 . K) (L . 15) (A . 16) (T . 23) (R . 53)
(N . 13) (M . 7) (I . 52) (35 . Q) (S . 19) (Y . 29) (45 . G) (44 . W)
(11 . V) (J . 25) (21 . F) (39 . Z) (25 . X) (50 . E) (5 . P) (33 . C)
(O . 34))
this being a list of pairs representing a Wason deck. (See this, Example 6). In the deck there should be all the letters of the alphabet matched with even or odd numbers depending on whether a vowel or consonant respectively. I randomly shuffle and flip the cards as you can see. Then I (optionally) randomly pollute the deck by occasionally breaking the vowel:even, consonant:odd rule. Here's the code I've come up with:
(defun wason-deck (&optional (p 0))
"This `consolst` and `vowlist` building is unnecessary, but a good exercise"
(let* ((alphab '(a b c d e f g h i j k l m n o p q r s t u v w x y z))
(consonents '(b c d f g h j k l m n p q r s t v w x y z))
(consolst (remove 'NIL (mapcar (lambda (x) (find x consonents)) alphab)))
(vowlst (remove 'NIL (mapcar (lambda (x) (find x '(a e i o))) alphab)))
(wdeck '()))
(labels ((make-consodeck ()
(mapcar (lambda (x) (let ((num (random 54)))
(cons x (if (evenp num)
(1+ num)
num)))) consolst))
(make-voweldeck ()
(mapcar (lambda (x) (let ((num (random 54)))
(cons x (if (oddp num)
(1+ num)
num)))) vowlst))
(swap (slst el1 el2)
(let ((tmp (elt slst el1)))
(setf (elt slst el1) (elt slst el2))
(setf (elt slst el2) tmp)))
(shuffle (slst)
(loop for i in (reverse (range (length slst) :min 1))
do (let ((j (random (+ i 1))))
(swap slst i j)))
slst)
(flip (flst)
(mapcar (lambda (x) (let ((num (random 2)))
(if (zerop num)
(cons (cdr x) (car x))
x))) flst)))
(setf wdeck (flip (shuffle (append (make-consodeck) (make-voweldeck)))))
(if (zerop p) wdeck
(mapcar (lambda (x) (let ((num (random 6)))
(cond ((and (zerop num) (numberp (car x))) (cons (1+ (car x)) (cdr x)))
((and (zerop num) (numberp (cdr x))) (cons (car x) (1+ (cdr x))))
(t x)))) wdeck)))))
It works, but what I fear is not really knowing what I'm doing, i.e., I've misused labels as well as done a setf in the code. If some of the more senior people could tell me whether this is totally off in the wrong direction or not.
Addendum:
This is what I've got after the suggestions from below:
(defun wason-deck3 (&optional (p 0))
(let* ((consonents '(b c d f g h j k l m n p q r s t v w x y z))
(vowels '(a e i o u))
(conso-deck (mapcar (lambda (x)
(cons x (1+ (* 2 (random 27)))))
consonents))
(vowel-deck (mapcar (lambda (x)
(cons x (* 2 (random 27))))
vowels))
(wdeck '()))
(labels
((shuffle (slst)
(loop :for i :from (1- (length slst)) :downto 1
:do (rotatef (nth i slst)
(nth (random (1+ i)) slst)))
slst)
(flip (flst)
(mapcar (lambda (x) (let ((num (random 2)))
(if (zerop num)
(cons (cdr x) (car x))
x))) flst)))
(setf wdeck (flip (shuffle (append conso-deck vowel-deck)))))
(if (zerop p) wdeck
(mapcar (lambda (x) (let ((num (random 6)))
(cond ((and (zerop num) (numberp (car x))) (cons (1+ (car x)) (cdr x)))
((and (zerop num) (numberp (cdr x))) (cons (car x) (1+ (cdr x))))
(t x)))) wdeck))))
Please add any new suggestions.

Using labels is totally OK, and your code is not entirely unreasonable.
A few pointers:
I'd represent characters as characters: '(#\a #\b #\c …)
I'd take my list exercises elsewhere, or at least use set-difference.
When you create a function for just one call, you might as well just save the result:
(let ((consonant-deck (mapcar (lambda (c)
(cons c (1+ (* 2 (random 27)))))
consonants))
(vowel-deck (mapcar (lambda (c)
(cons c (* 2 (random 27))))
vowels)))
…)
For swapping, there is rotatef: (rotatef (nth i list) (nth j list)). Such things are rather expensive on lists, so I'd prefer to use a vector for this. Then it comes in handy that a string is just a vector of characters…
Loop can do counting for you, you don't need to create lists:
(loop :for i :from (1- (length list)) :downto 1
:do (rotatef (nth i list)
(nth (random (1+ i)) list)))
(Using keywords as loop keywords is optional, but indentation should be like this.)
If you put the labels around the let, you can immediately bind wdeck, so that you do not need to setf it afterwards.
You do not need this function for the exercise that you linked to.

Related

Sum of multiples of 3 & 5 using LISP

(defun modsum2 (n)
(let ((summ 0))
(if (>= n 3)
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ))))
I am trying to get the sum of multiples of 3 and 5 below the given number. But the code always returns to 0. What is the problem with it?
(defun modsum2 (n)
(let ((summ 0))
(if (>= n 3)
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ))))
Right, now you got it indented. Let's trace it:
* (trace modsum2)
(MODSUM2)
* (modsum2 4)
0: (MODSUM2 4)
1: (MODSUM2 3)
2: (MODSUM2 2)
0 2: MODSUM2 returned 0
1: MODSUM2 returned 0
0: MODSUM2 returned 0
0
You can see that 0 gets printed when the argument to n is 2. Since the print form is also the last form, the function returns its value. (print 0) returns 0. Since the return value is in your function used, it just gets returned from each recursive call.
A typical way to repair it would be to have a local recursive function using labels inside the let. You then need to call the function. Later you would need to return the summ.
;; your function has some flaws
(defun modsum2 (n)
(let ((summ 0)) ;; in every call, `summ` is put to `0`!
(if (>= n 3) ;; for n = 2, the alternative `(print summ)` is executed
(if (or (zerop (mod n 3)) (zerop (mod n 5)))
(progn (setq summ (+ n summ))
(modsum2 (1- n)))
(modsum2 (1- n)))
(print summ)))) ;; for n = 2 already this is called
;; since summ is set to `0` for this last modsum2 call, it prints 0
;; tail call recursion with inner function
(defun modsum2 (n)
(let ((summ 0))
(labels ((.modsum2 (.n)
(cond ((zerop .n) summ)
((or (zerop (mod .n 3)) (zerop (mod .n 5)))
(setq summ (+ .n summ))
(.modsum2 (1- .n)))
(t (.modsum2 (1- .n))))))
(print (.modsum2 n)))))
;; tail call recursion with optional accumulator for the proper start
(defun modsum2 (n &optional (acc 0))
(cond ((zerop n) acc)
((or (zerop (mod n 3))
(zerop (mod n 5)))
(modsum2 (1- n) (+ acc n)))
(t (modsum2 (1- n) acc))))
;; using loop
(defun modsum2 (n)
(loop for x from 1 to n
when (or (zerop (mod x 3)) (zerop (mod x 5)))
sum x into res
finally (return res)))
;; which is equivalent to (thanks #Rainer Joswig):
(defun modsum2 (n)
(loop for x from 1 to n
when (or (zerop (mod x 3)) (zerop (mod x 5)))
sum x))
;; using reduce or apply
(defun modsum2 (n)
(reduce #'+ (remove-if-not #'(lambda (x) (or (zerop (mod x 3))
(zerop (mod x 5))))
(loop for x from 1 to n))))
;; instead of `reduce`, `apply` would work, too.
You’re doing far too much work. Just do inclusion-exclusion:
(defun modsum2 (max)
(let ((a (floor max 3))
(b (floor max 5))
(c (floor max 15)))
(/ (- (+ (* 3 a (1+ a))
(* 5 b (1+ b)))
(* 15 c (1+ c)))
2)))
To extend this a bit to more than just 3,5:
(defun multsum (k max)
"The sum of multiples of `k' below `max'"
(let ((a (floor max k)))
(* k a (1+ a))))
(defun subsequences-reduce (f items)
(unless items (return ()))
(loop for (item . rest) on items
collect (cons 1 item)
nconc (loop for (len . val) in (subsequences-reduce f rest)
collect (cons (1+ len) (funcall f item val)))))
(defun modsum (max &rest nums)
(loop for (len . lcm) in (subsequences-reduce #'lcm nums)
sum (* (if (oddp len) 1 -1) (multsum lcm max))))
(defun modsum2 (max) (modsum max 3 5))
I have solved the same problem last week for project euler. I have noticed the way I wrote it does not included in answers. Dropping it here, it might be useful.
;;finds the multiple of 3's and 5's below the number n
;;since "or" turns t, whenever one of its arguments returns t. No need to substract multiple of 15.
(defun modsum2 (n)
(cond ((< n 3) 0)
(t (do ((i 3 (1+ i))
(summ 0))
((> i n) summ)
(cond ((or (zerop (mod i 3))
(zerop (mod i 5)))
(setq summ (+ summ i))))))))

Building the built-in procedure "build-list" in Racket

I am trying to build the built-in procedure build-list in Racket.
The built-in function works like this:
(build-list 10 (lambda (x) (* x x)))
>> '(0 1 4 9 16 25 36 49 64 81)
My implementation is a recursive definition for a recursive procedure:
(define (my-build-list-recur list-len proc)
(if (= list-len 0)
'()
(cons (proc (sub1 list-len)) (my-build-list-recur (sub1 list-len) proc))))
When I call my implementation, I have:
(my-build-list-recur 10 (lambda (x) (* x x)))
>> '(81 64 49 36 25 16 9 4 1 0)
As you might have seen, I get the same result, but in a reverse order.
What can I do to have the result in the same order as the native function?
P.S.: I have done an implementation using a recursive definition for an iterative procedure which works perfectly. I am struggling now to generate the same result with the totally recursive procedure. I already know how to solve this doubt with long tail recursion.
This is my implementation with long tail recursion:
(define (my-build-list list-len proc)
(define (iter list-len accu n)
(if (= (length accu) list-len)
(reverse accu)
(iter list-len (cons (proc n) accu) (add1 n))))
;(trace iter)
(iter list-len '() 0))
Ok so you're looking for an answer that does not use state variables and a tail call. You want for a recursive procedure that also evolves a recursive process. Not sure why you want this other than just to see how the definition would differ. You should also read about tail recursion modulo cons (here, and on wikipedia) – it's relevant to this question.
;; recursive procedure, recursive process
(define (build-list n f)
(define (aux m)
(if (equal? m n)
empty
(cons (f m) (aux (add1 m)))))
(aux 0))
(build-list 5 (λ (x) (* x x)))
;; => '(0 1 4 9 16)
Notice how the aux call is no longer in tail position – ie, cons cannot finish evaluating until it has evaluated the aux call in its arguments. The process will look something like this, evolving on the stack:
(cons (f 0) ...)
(cons (f 0) (cons (f 1) ...))
(cons (f 0) (cons (f 1) (cons (f 2) ...)))
(cons (f 0) (cons (f 1) (cons (f 2) (cons (f 3) ...))))
(cons (f 0) (cons (f 1) (cons (f 2) (cons (f 3) (cons (f 4) ...)))))
(cons (f 0) (cons (f 1) (cons (f 2) (cons (f 3) (cons (f 4) empty)))))
(cons (f 0) (cons (f 1) (cons (f 2) (cons (f 3) (cons (f 4) '())))))
(cons (f 0) (cons (f 1) (cons (f 2) (cons (f 3) '(16)))))
(cons (f 0) (cons (f 1) (cons (f 2) '(9 16))))
(cons (f 0) (cons (f 1) '(4 9 16)))
(cons (f 0) '(1 4 9 16))
'(0 1 4 9 16)
You'll see that the cons calls are left hanging open until ... is filled in. And the last ... isn't filled in with empty until m is equal to n.
If you don't like the inner aux procedure, you can use a default parameter, but this does leak some of the private API to the public API. Maybe it's useful to you and/or maybe you don't really care.
;; recursive procedure, recursive process
(define (build-list n f (m 0))
(if (equal? m n)
'()
(cons (f m) (build-list n f (add1 m)))))
;; still only apply build-list with 2 arguments
(build-list 5 (lambda (x) (* x x)))
;; => '(0 1 4 9 16)
;; if a user wanted, they could start `m` at a different initial value
;; this is what i mean by "leaked" private API
(build-list 5 (lambda (x) (* x x) 3)
;; => '(9 16)
Stack-safe implementations
Why you'd specifically want a recursive process (one which grows the stack) is strange, imo, especially considering how easy it is to write a stack-safe build-list procedure which doesn't grow the stack. Here's some recursive procedures with a linear iterative processes.
The first one is extremely simple but does leak a little bit of private API using the acc parameter. You could easily fix this using an aux procedure like we did in the first solution.
;; recursive procedure, iterative process
(define (build-list n f (acc empty))
(if (equal? 0 n)
acc
(build-list (sub1 n) f (cons (f (sub1 n)) acc))))
(build-list 5 (λ (x) (* x x)))
;; => '(0 1 4 9 16)
Check out the evolved process
(cons (f 4) empty)
(cons (f 3) '(16))
(cons (f 2) '(9 16))
(cons (f 1) '(4 9 16))
(cons (f 0) '(1 4 9 16))
;; => '(0 1 4 9 16)
This is insanely better because it can constantly reuse one stack frame until the entire list is built. As an added advantage, we don't need to keep a counter that goes from 0 up to n. Instead, we build the list backwards and count from n-1 to 0.
Lastly, here's another recursive procedure that evolves a linear iterative process. It utilizes a named-let and continuation passing style. The loop helps prevent leaking the API this time.
;; recursive procedure, iterative process
(define (build-list n f)
(let loop ((m 0) (k identity))
(if (equal? n m)
(k empty)
(loop (add1 m) (λ (rest) (k (cons (f m) rest)))))))
(build-list 5 (λ (x) (* x x)))
;; => '(0 1 4 9 16)
It cleans up a little tho if you use compose and curry:
;; recursive procedure, iterative process
(define (build-list n f)
(let loop ((m 0) (k identity))
(if (equal? n m)
(k empty)
(loop (add1 m) (compose k (curry cons (f m)))))))
(build-list 5 (λ (x) (* x x)))
;; => '(0 1 4 9 16)
The process evolved from this procedure is slightly different, but you'll notice that it also doesn't grow the stack, creating a sequence of nested lambdas on the heap instead. So this would be sufficient for sufficiently large values of n:
(loop 0 identity) ; k0
(loop 1 (λ (x) (k0 (cons (f 0) x))) ; k1
(loop 2 (λ (x) (k1 (cons (f 1) x))) ; k2
(loop 3 (λ (x) (k2 (cons (f 2) x))) ; k3
(loop 4 (λ (x) (k3 (cons (f 3) x))) ; k4
(loop 5 (λ (x) (k4 (cons (f 4) x))) ; k5
(k5 empty)
(k4 (cons 16 empty))
(k3 (cons 9 '(16)))
(k2 (cons 4 '(9 16)))
(k1 (cons 1 '(4 9 16)))
(k0 (cons 0 '(1 4 9 16)))
(identity '(0 1 4 9 16))
'(0 1 4 9 16)

Unexpected error in simple recursion(Scheme Language)

I'm learning Scheme using racket. I made the following program but it gives a contract violation error.
expected: (exact-nonnegative-integer? . -> . any/c)
given: '()
The program finds a list of all numbers in an interval which are divisible by 3 or 5.
#lang racket
;;Global Definitions
(define upper-bound 10)
(define lower-bound 0)
;;set-bounds: Int, Int -> ()
(define (set-bounds m n)
(set! upper-bound (max m n))
(set! lower-bound (min m n)))
;;get-numbers: () -> (Int)
(define (get-numbers)
(build-list upper-bound '()))
;;make-list: Int, (Int) -> (Int)
(define (build-list x y)
(cond
[(= x lower-bound) y]
[(= (modulo x 5) 0) (build-list (sub1 x) (cons x y))]
[(= (modulo x 3) 0) (build-list (sub1 x) (cons x y))]
[else (build-list (sub1 x) y)]))
EDIT: I made the changes suggested by Oscar Lopez.
An alternative method can be with the use of for/list to create the list:
(define (build-list ub lst)
(for/list ((i (range lb ub))
#:when (or (= 0 (modulo i 3))
(= 0 (modulo i 5))))
i))
Usage:
(define lb 0)
(build-list 10 '())
Output:
'(0 3 5 6 9)
Edit:
Actually lst is not needed here:
(define (build-list ub)
(for/list ((i (range lb ub))
#:when (or (= 0 (modulo i 3))
(= 0 (modulo i 5))))
i))
So one can call:
(build-list 10)
Following is a modification of the recursion method (uses 'named let'):
(define (build-list2 ub)
(let loop ((x ub) (lst '()))
(cond
[(= x lb) lst]
[(= (modulo x 5) 0) (loop (sub1 x) (cons x lst))]
[(= (modulo x 3) 0) (loop (sub1 x) (cons x lst))]
[else (loop (sub1 x) lst)])))
Also, if you always have to call your function with an empty list '(), you can put this as default in your argument list:
(build-list x (y '()))
Then you can call with simplified command:
(build-list 10)
You should test first the condition where the recursion stops - namely, when x equals the lower-bound:
(define (build-list x y)
(cond
[(= x lower-bound) y]
[(= (modulo x 5) 0) (build-list (sub1 x) (cons x y))]
[(= (modulo x 3) 0) (build-list (sub1 x) (cons x y))]
[else (build-list (sub1 x) y)]))

recursively count sublists beginning with a number

I am trying to write code in Lisp counting sublists beginning with number, recursively. I ve trying to use numberp but my code, when arrived to an atom, doesn't count the rest of the list.
With my code here,
(defun nombres (liste)
(cond
((atom liste) 0)((atom (car liste)) 0)
((and (numberp (caar liste)) (+ (nombres (cdr liste)) 1)))
(t (nombres (cdr liste))) ) )
I can get a count of sublists but when arrived to an atom , it doesn't count the rest.
[67]> (nombres '((a b d) (5 g) (7 m)))
2
[68]> (nombres '((a b d) (5 g) g (7 m)))
1
When I test the sublist with (listp (car list), it gives me nil.
[69]> (defun nombres (liste)
(cond
((atom liste) 0)((atom (car liste)) 0)
((listp (car liste))(and (numberp (caar liste)) (+ (nombres (cdr liste)) 1))) (t (nombres (cdr liste))) ) )
NOMBRES
[70]> (nombres '((a b d) (5 g) g (7 m) m))
NIL
I want to get something like :
(nombres '((a b d) a (5 g) (b) (7 m) j (8 h l g)))
3
Thanks for your help
You need to think about the cases you need to handle.
The end of the list => return the result
A sublist that has a number in front => add one to the result
Anything else => continue to the next element
These will quite easily translate to a COND:
(cond ((endp list) ...) ; 1
((and (listp (car list)) ; 2
(numberp (caar list)))
...)
(t ...) ; 3
Using an accumulator as an optional parameter, the counting is easy to fill in:
(defun count-sublists (list &optional (acc 0))
(cond ((endp list) acc)
((and (listp (car list))
(numberp (caar list)))
(count-sublists (cdr list) (1+ acc)))
(t (count-sublists (cdr list) acc))))
(count-sublists '((a b d) a (5 g) (b) (7 m) j (8 h l g)))
;=> 3
The standard Common Lisp function count-if is easier to use:
CL-USER > (count-if (lambda (item)
(and (consp item)
(numberp (first item))))
'((a b d) a (5 g) (b) (7 m) j (8 h l g)))
3

how to merge two strings ordered alphabetically, using recursion

I am learning Lisp. I have implemented a Common Lisp function that merges two strings that are ordered alphabetically, using recursion. Here is my code, but there is something wrong with it and I didn't figure it out.
(defun merge (F L)
(if (null F)
(if (null L)
F ; return f
( L )) ; else return L
;else if
(if (null L)
F) ; return F
;else if
(if (string< (substring F 0 1) (substring L 0 1)
(concat 'string (substring F 0 1)
(merge (substring F 1 (length F)) L)))
(
(concat 'string (substring L 0 1)
(merge F (substring L 1 (length L)) ))
))))
Edit :
I simply want to merge two strings such as the
inputs are string a = adf and string b = beg
and the result or output should be abdefg.
Thanks in advance.
Using string< is an overkill, char< should be used instead, as shown by Kaz. Recalculating length at each step would make this algorithm quadratic, so should be avoided. Using sort to "fake it" makes it O(n log n) instead of O(n). Using concatenate 'string all the time probably incurs extra costs of unneeded traversals too.
Here's a natural recursive solution:
(defun str-merge (F L)
(labels ((g (a b)
(cond
((null a) b)
((null b) a)
((char< (car b) (car a))
(cons (car b) (g a (cdr b))))
(t (cons (car a) (g (cdr a) b))))))
(coerce (g (coerce F 'list) (coerce L 'list))
'string)))
But, Common Lisp does not have a tail call optimization guarantee, let alone tail recursion modulo cons optimization guarantee (even if the latter was described as early as 1974, using "Lisp 1.6's rplaca and rplacd field assignment operators"). So we must hand-code this as a top-down output list building loop:
(defun str-merge (F L &aux (s (list nil)) ) ; head sentinel
(do ((p s (cdr p))
(a (coerce F 'list) (if q a (cdr a)))
(b (coerce L 'list) (if q (cdr b) b ))
(q nil))
((or (null a) (null b))
(if a (rplacd p a) (rplacd p b))
(coerce (cdr s) 'string)) ; FTW!
(setq q (char< (car b) (car a))) ; the test result
(if q
(rplacd p (list (car b)))
(rplacd p (list (car a))))))
Judging by your comments, it looks like you're trying to use if with a series of conditions (like a series of else ifs in some other languages). For that, you probably want cond.
I replaced that if with cond and cleaned up some other errors, and it worked.
(defun empty (s) (= (length s) 0))
(defun my-merge (F L)
(cond
((empty F)
(if (empty L)
F
L))
((empty L)
F)
(t
(if (string< (subseq F 0 1) (subseq L 0 1))
(concatenate 'string (subseq F 0 1) (my-merge (subseq F 1 (length F)) L))
(concatenate 'string (subseq L 0 1) (my-merge F (subseq L 1 (length L))))))))
Your test case came out as you wanted it to:
* (my-merge "adf" "beg")
"abdefg"
There were quite a few good answers, so why would I add one more? Well, the below is probably more efficient then the other answers here.
(defun merge-strings (a b)
(let* ((lena (length a))
(lenb (length b))
(len (+ lena lenb))
(s (make-string len)))
(labels
((safe-char< (x y)
(if (and x y) (char< x y)
(not (null x))))
(choose-next (x y)
(let ((ax (when (< x lena) (aref a x)))
(by (when (< y lenb) (aref b y)))
(xy (+ x y)))
(cond
((= xy len) s)
((safe-char< ax by)
(setf (aref s xy) ax)
(choose-next (1+ x) y))
(t
(setf (aref s xy) by)
(choose-next x (1+ y)))))))
(choose-next 0 0))))
(merge-strings "adf" "beg")
It is more efficient specifically in the sense of memory allocations - it only allocates enough memory to write the result string, never coerces anything (from list to string or from array to string etc.) It may not look very pretty, but this is because it is trying to do every calculation only once.
This is, of course, not the most efficient way to write this function, but programming absolutely w/o efficiency in mind is not going to get you far.
A recursive way to do it (fixed according to comment- other solutions can get an IF form as well).
(defun merge-strings (a b)
(concatenate 'string
(merge-strings-under a b)))
(defun merge-strings-under (a b)
(when (and
(= (length a)
(length b))
(> (length a) 0))
(append (if (string< (aref a 0) (aref b 0))
(list (aref a 0) (aref b 0))
(list (aref b 0) (aref a 0)))
(merge-strings-under (subseq a 1)
(subseq b 1)))))
Here's a iterative way to do it.
(concatenate 'string
(loop for i across "adf" for j across "beg" nconc (list i j)))
Note that these rely on building the string into a list of characters, then vectorizing it ( a string is a vector of characters).
You can also write a more C-esque approach...
(defun merge-strings-vector (a b)
(let ((retstr (make-array (list (+
(length a)
(length b)))
:element-type 'character)))
(labels ((merge-str (a b i)
(when (and
(= (length a)
(length b))
(/= i (length a)))
(setf (aref retstr (* 2 i)) (aref a i))
(setf (aref retstr (1+ (* 2 i))) (aref b i))
(merge-str a b (1+ i)))))
(merge-str a b 0)
retstr)))
Note that this one - unlike the other 2 - has side effects within the function. It also, imo, is more difficult to understand.
All 3 take varying numbers of cycles to execute on SBCL 56; each seems to take between 6K and 11K on most of my trials. I'm not sure why.

Resources