Data Structure:1. Functional-Style Linked Lists

1. Functional-Style Linked Lists

We frequently use linked lists in our programs, but Scheme makes that easy because it provides linked lists as a native data type, along with a rich set of operations on them. In today’s exercise we will implement lists in the functional style that Scheme provides natively.

In Scheme, a list is really nothing more than an array with two slots, known as the car and cdr of a pair; a list with no elements is called the null list. We frequently think of lists as a sequence of elements, but in fact a list is no more than a chain of pairs, of which the cdr of each pair is another list, the chain terminating in a null list. Depending on the version of Scheme that you use, the car and cdr of the pair may or may not be mutable; traditionally, they have been mutable, but the most recent approved standard R6RS makes pairs immutable (that is controversial, and many implementations of Scheme ignore it and leave pairs mutable). Still, immutable pairs are more closely aligned with the spirit of functional languages, and your implementation today should provide immutable pairs.

Your task is to implement a small library of list operators; you should include at least nil and a predicate to recognize it, a procedure to build pairs and two procedures to extract the pieces of a pair, functions to extract the nth item of a list and to determine its length, and functions to reverse the elements of a list and append two lists; you are welcome to provide more operators if you wish. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

We represent a pair as a vector with two slots. The null pair is represented as a zero-length vector. Head and tail extract the various elements:

(define nil (vector)) ; '()

(define (nil? xs) (zero? (vector-length xs))) ; null?

(define (pair x xs) (vector x xs)) ; cons

(define (head xs) ; car
  (if (nil? xs)
      (error 'head "exhausted")
      (vector-ref xs 0)))

(define (tail xs) ; cdr
  (if (nil? xs)
      (error 'tail "exhausted")
      (vector-ref xs 1))

With that, we can build a list like this:

> (define xs (pair 0 (pair 1 (pair 2 (pair 3 (pair 4 (pair 5 (pair 6 (pair 7 nil)))))))))
> (head xs)
0
> (head (tail (tail (tail xs))))
3

The nth item is found by counting down the elements of a list until the desired item is found; the length of a list is found by counting each element until the last is found. Old-time lispers call the operation of inspecting each element of a list cdr-ing down the list:

(define (nth xs n) ; list-ref
  (if (nil? xs)
        (error 'nth "exhausted")
      (if (zero? n)
          (head xs)
          (nth (tail xs) (- n 1))))

(define (len xs) ; length
  (if (nil? xs)
      0
      (+ (len (tail xs)) 1)))

> (nth xs 5)
5
> (len xs)
8

The append function must cdr down the first list; the second list is untouched:

(define (app x1 x2) ; append
  (if (nil? x1)
      x2
      (pair (head x1)
            (app (tail x1) x2))))

> (nth (app xs (pair 8 (pair 9 nil))) 9)
9
> (nth (app xs (pair 8 (pair 9 nil))) 10)
error: nth: exhausted

A naive reverse calls append for each item in the list; an iterative reverse simply cdrs down the input as it accumulates the output:

(define (rev-recursive xs) ; reverse
  (if (nil? xs)
      nil
      (app (rev-recursive (tail xs))
           (pair (head xs) nil))))

(define (rev-iterative xs) ; reverse
  (let loop ((xs xs) (rs nil))
    (if (nil? xs)
        rs
        (loop (tail xs) (pair (head xs) rs)))))

> (nth (rev-recursive xs) 4)
3
> (nth (rev-iterative xs) 4)
3

We’ll stop there; the Standard Prelude gives many more examples of list operations.

; functional-style linked lists

(define (error symb str)
  (display "error: ")
  (display (symbol->string symb))
  (display ": ")
  (display str)
  (newline))

(define nil (vector)) ; '()

(define (nil? xs) (zero? (vector-length xs))) ; null?

(define (pair x xs) (vector x xs)) ; cons

(define (head xs) ; car
  (if (nil? xs)
      (error 'head "exhausted")
      (vector-ref xs 0)))

(define (tail xs) ; cdr
  (if (nil? xs)
      (error 'tail "exhausted")
      (vector-ref xs 1)))

(define xs (pair 0 (pair 1 (pair 2 (pair 3 (pair 4 (pair 5 (pair 6 (pair 7 nil)))))))))
(display (head xs)) (newline)
(display (head (tail (tail (tail xs))))) (newline)

(define (nth xs n) ; list-ref
  (if (nil? xs)
    (error 'nth "exhausted")
    (if (zero? n)
        (head xs)
        (nth (tail xs) (- n 1)))))

(define (len xs) ; length
  (if (nil? xs)
      0
      (+ (len (tail xs)) 1)))

(display (nth xs 5)) (newline)
(display (len xs)) (newline)

(define (app x1 x2) ; append
  (if (nil? x1) x2
    (pair (head x1)
          (app (tail x1) x2))))

(display (nth (app xs (pair 8 (pair 9 nil))) 9)) (newline)
(display (nth (app xs (pair 8 (pair 9 nil))) 10)) (newline)

(define (rev-recursive xs) ; reverse
  (if (nil? xs) nil
    (app (rev-recursive (tail xs))
         (pair (head xs) nil))))

(define (rev-iterative xs) ; reverse
  (let loop ((xs xs) (rs nil))
    (if (nil? xs)
        rs
        (loop (tail xs) (pair (head xs) rs)))))

(display (nth (rev-recursive xs) 4)) (newline)
(display (nth (rev-iterative xs) 4)) (newline)

output:

0
3
5
8
9
error: nth: exhausted
#<void>
3
3

See more on [ProgrammingProxis](http://programmingpraxis.com/contents/themes/#Data Structures)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 我的读书,追溯到最早,应该是童年。 我们那个时候读的是小人书。一本巴掌大的小人书摆放在供销社的玻璃柜台里,看一眼都...
    蒲阳凡妈阅读 4,039评论 14 20
  • 落日归来 林间小道 我们,一起回家
    伍月的晴空阅读 1,209评论 0 1
  • 屋顶露台, 乌云压顶, 几枚凋落的花瓣, 听一首老掉牙的歌, 此刻,时光可以停留~
    公子小白r阅读 942评论 0 0
  • 今天分享的书目:《零秒思考》 作者:日本赤羽雄二 要想训练自己能够快速解决问题的好方法,很简单。请你先做好以下准备...
    一溪风月阅读 1,579评论 3 6
  • 我二十岁的独自北京之行要结束了。我现在能做的,就是在国图对面吃过饭码着字等着差不多时候去车站。 大学之后再也没有作...
    碎瓜rororo阅读 2,744评论 0 0