Dr Racket 列表函数

Dr Racket list function

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.

我觉得这应该很容易,但我一直在获取列表列表,因此检查预期不起作用。我在这个问题上被困了一个多小时。我试过 append 和 list* 以及其他一些东西,但我无法弄清楚如何将一个列表的列表折叠成一个列表,或者只是让函数与检查期望一起工作。 BSL+ 对此的任何帮助都会非常有用。无论如何,这就是我所拥有的:

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

这是我的版本:

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

你非常接近,而且你在考虑 list* 的方向上是正确的。事实上,在您的尝试中将 list 替换为 list* 会产生这个程序,它几乎完全正确:

(define (likenate lst)
  (cond [(empty? lst) '()]
        [else (list* (first lst) 'like (likenate (rest lst)))]))

您可以将 list* 视为多个 cons 的 shorthand。简单来说,(list* a b c)等价于(cons a (cons b c))。这是必要的,因为 likenate 的结果是 list,因此它需要是通过将两个新元素添加到这个列表。

该实现 几乎 有效,但有一个小问题。它会在列表的末尾插入 'like 元素,所以你最终会得到这样的列表,而不是:

(list 'here 'like 'be 'like 'dragons 'like)

只需在 cond 中添加一个额外的子句来专门处理最后一个元素,一切都应该正常工作:

(define (likenate lst)
  (cond [(empty? lst) '()]
        [(empty? (rest lst)) lst]
        [else (list* (first lst) 'like (likenate (rest lst)))]))

这是另一个使用宏的解决方案 define-syntax:

(define-syntax likenate
    (syntax-rules () 
      [(_ ()) '()]      
      [(_ (e1 e2 ...)) (cons e1 (cons 'like (likenate (e2 ...))))]))

一个区别是调用这个函数时,不需要调用list函数:

(likenate ('here 'be 'dragons)) => (here like be like dragons like)