List passed to procedure converts into list of lis

2019-07-19 02:08发布

问题:

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?

回答1:

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).



回答2:

I think it will be better to raise an error when calling your procedure on an empty list –

(define last-element-of-list
  (lambda (l)
    (cond ((null? l)
           (error 'last-element-of-list "cannot get last element of empty list"))
          ((null? (cdr l))
           (car l))
          (else
           (last-element-of-list (cdr l))))))


(last-element-of-list '(1))         ;; 1
(last-element-of-list '(1 2))       ;; 2
(last-element-of-list '(1 2 3))     ;; 3
(last-element-of-list '(1 2 3 4))   ;; 4

(last-element-of-list '())          ;; error: cannot get last element of empty list