2
votes

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)))
  ]))
3

3 Answers

2
votes

Here's my version:

(define (likenate lst)
  (cond ((empty? (rest lst)) lst)
        (else (list* (first lst) 'like (likenate (rest lst))))))
2
votes

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 conses. 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)))]))
0
votes

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)