Racket 编程

1 部分 · Racket 核心

列表与递归

列表与递归

深入列表操作与递归思维,包括尾递归优化和常用列表高阶函数。

列表:Racket 的灵魂

#lang racket

;; 构造列表
'(1 2 3)                         ; 引用构造
(list 1 2 3)                     ; 函数构造
(cons 0 '(1 2 3))                ; => '(0 1 2 3)

;; 拆解列表
(car '(1 2 3))                   ; => 1
(cdr '(1 2 3))                   ; => '(2 3)

递归思维

递归是处理列表的核心方式:

;; 求列表长度
(define (my-length lst)
  (if (null? lst)
      0
      (+ 1 (my-length (cdr lst)))))

;; 反转列表
(define (my-reverse lst)
  (if (null? lst)
      '()
      (append (my-reverse (cdr lst))
              (list (car lst)))))

尾递归优化

尾递归不会导致栈溢出,因为它可以被编译器优化为循环:

;; 非尾递归(可能溢出)
(define (sum lst)
  (if (null? lst)
      0
      (+ (car lst) (sum (cdr lst)))))

;; 尾递归(安全)
(define (sum-tail lst)
  (let loop ([rest lst] [acc 0])
    (if (null? rest)
        acc
        (loop (cdr rest) (+ acc (car rest))))))

(sum-tail '(1 2 3 4 5))  ; => 15

列表高阶函数

;; map
(map (lambda (x) (* x x)) '(1 2 3 4 5))
; => '(1 4 9 16 25)

;; filter
(filter even? '(1 2 3 4 5 6))
; => '(2 4 6)

;; foldl / foldr
(foldl + 0 '(1 2 3 4 5))  ; => 15
(foldl cons '() '(1 2 3)) ; => '(3 2 1)
(foldr cons '() '(1 2 3)) ; => '(1 2 3)

;; andmap / ormap
(andmap positive? '(1 2 3))   ; => #t
(ormap even? '(1 3 5 7 8))    ; => #t

常用列表操作

(append '(1 2) '(3 4))     ; => '(1 2 3 4)
(reverse '(1 2 3))          ; => '(3 2 1)
(sort '(3 1 4 1 5) <)      ; => '(1 1 3 4 5)
(take '(1 2 3 4 5) 3)       ; => '(1 2 3)
(drop '(1 2 3 4 5) 3)       ; => '(4 5)
(assoc 'b '((a 1) (b 2)))   ; => '(b 2)

小结

列表和递归是 Racket 编程的基石。掌握 car/cdr/cons 三件套、尾递归优化和 map/filter/fold 高阶函数,是成为高效 Racket 程序员的关键。