首页 > 解决方案 > List passed to procedure converts into list of list inside the procedure

问题描述

I'm debugging this code on DrRacket:

#lang racket

(define last-element-on-list
   (lambda l
      (cond ((null? l) '())
            ((null? (cdr l)) (car l))
            (else (last-element-on-list (cdr l)))
      )
   )
)

(define lst '(
  (n 25 f +)
  (s 25 m +)
  (ll 20 no -)))

(list-ref lst 0)

(last-element-on-list (list-ref lst 0))

The code (list-ref lst 0) returns '(n 25 f +), but when I get into the procedure last-element-on-list the parameter l has the value ((n 25 f +)).

Why l is a list of list in procedure last-element-on-list?

标签: listschemeracket

解决方案


There's a difference between the (lambda (x) ...) form and the (lambda x ...) form.

Observe the difference between these two examples:

;; Example 1.
(define f
  (lambda (x)
    (if (list? x)
      (display "x is a list!")
      (display "x is not a list"))))

(f 1)  ; Displays "x is not a list".

;; Example 2.
(define g
  (lambda x
    (if (list? x)
      (display "x is a list!")
      (display "x is not a list"))))

(g 1)  ; Displays "x is a list!".

The (lambda x ...) form allows the lambda to take any number of arguments, with all the arguments put into a list bound to x in the lambda's body. i.e. x is the list of arguments.

That's why when you give g a list (e.g. (g '(1 2 3))), x will be '((1 2 3)) (a list of lists).

To fix your code:

(define last-element-on-list
   (lambda (l)  ; <- ATTENTION.
      (cond ((null? l) '())  ; FIXME: raise error instead.
            ((null? (cdr l)) (car l))
            (else (last-element-on-list (cdr l))))))

You can read more about lambda in The Racket Guide. In particular, look at section 4.4.1 (Declaring a Rest Argument).


推荐阅读