Reputation: 119
Define a procedure
likenate
that takes a list and returns the list with the symbol'like
inserted between each pair of adjacent elements in the given list.
I feel like this should be really easy, but I keep getting lists of lists so the check-expects aren't working. I've been stuck on this problem for over an hour. I've tried append and list* and some other things, but I can't figure out how to collapse a list of a list into one list or just get the function to work with the check-expects. Any help on this in BSL+ would be so great. Anyway, this is what I have:
; likenate : List -> List
(check-expect (likenate (list 'here 'be 'dragons))
(list 'here 'like 'be 'like 'dragons))
(check-expect (likenate (list 'that 'is 'so 'cool))
(list 'that 'like 'is 'like 'so 'like 'cool))
(check-expect (likenate (list 'like 'like))
(list 'like 'like 'like))
(define (likenate list_like)
(cond [(empty? list_like) '()]
[else (list (first list_like) 'like (likenate (rest list_like)))
]))
Upvotes: 2
Views: 1253
Reputation: 2452
Here is another solution using macros and define-syntax
:
(define-syntax likenate
(syntax-rules ()
[(_ ()) '()]
[(_ (e1 e2 ...)) (cons e1 (cons 'like (likenate (e2 ...))))]))
One difference is that when calling this function, you don't need to call the list
function:
(likenate ('here 'be 'dragons))
=> (here like be like dragons like)
Upvotes: 0
Reputation: 43902
You're very close, and you're on the right track thinking about list*
. In fact, replacing list
with list*
in your attempt yields this program, which is almost exactly correct:
(define (likenate lst)
(cond [(empty? lst) '()]
[else (list* (first lst) 'like (likenate (rest lst)))]))
You can think of list*
as a shorthand for multiple cons
es. To put it simply, (list* a b c)
is equivalent to (cons a (cons b c))
. This is necessary because the result of likenate
is a list, so it needs to be the cdr
element of the cons pair created by prepending the two new elements to this list.
That implementation almost works, with one small problem. It will insert 'like
elements at the end of the list, so you'll end up with lists like this, instead:
(list 'here 'like 'be 'like 'dragons 'like)
Just add an extra clause to the cond
to handle the last element specially, and everything should work properly:
(define (likenate lst)
(cond [(empty? lst) '()]
[(empty? (rest lst)) lst]
[else (list* (first lst) 'like (likenate (rest lst)))]))
Upvotes: 2
Reputation: 223183
Here's my version:
(define (likenate lst)
(cond ((empty? (rest lst)) lst)
(else (list* (first lst) 'like (likenate (rest lst))))))
Upvotes: 2