ペアとは2つのデータをまとめた構造体のことである。ドットペアと呼ばれることもある。
ペアに対する基本操作を以下にまとめる:
以下を Definitions に記述し、Run してみよう。
| (define p1 (cons 100 200)) (car p1) (cdr p1) | 
ペアを組み合わせて、データを並べた構造体をリストと呼ぶ。
たとえば、次のようにペアを使うと、数字のリストになる。
| (define p2 (cons 1 (cons 2 (cons 3 (cons 4 ()))))) | 
() は空を表す
このように、リストの正体は、ペアの集りであるが、分りにくい。そこで、次のように書くことができる。
| (define p3 (list 1 2 3 4)) | 
 
equal? を使って p2 と p3 が等しいことを確認しよう。
| > (equal? p2 p3) | 
リストに対する基本操作を以下にまとめる:
リストの個々のデータを扱う関数を作ってみよう。
| 
(define list-sum
  (lambda (lst)
    (if (null? lst)
        0
        (+ (car lst) (list-sum (cdr lst))))))    
 | 
実行方法: (list-sum (list 1 2 3 4 5))
予想結果: 15
| 
(define list-print
  (lambda (lst)
    (if (not (null? lst))
        ((lambda ()                     ここの lambda は
           (write '<)                   これら write と list-print の順接を
           (write (car lst))            実行するために
           (write '>)                   使われている。
           (list-print (cdr lst)))))))  lambda の前に括弧が2つあることに注意
 | 
実行方法: (list-print (list 1 2 3 4 5))
予想結果: <1><2><3><4><5>
| 
(define list-max
  (lambda (lst)
    (if (null? (cdr lst))           もし長さが1のリストならば、
        (car lst)                   リストの先頭の数値が最大値である。
        ((lambda (m n)              そうでなければ、2つの数値 m と n について
           (if (> m n) m n))        大きい数値を返す関数に、
         (car lst)                  リストの先頭の数値と
         (list-max (cdr lst))))))   リストの2番目以降の最大値を比較してもらう。
 | 
実行方法: (list-max (list 1 2 4 5 3))
予想結果: 5
上記の list-max の意味がわからない人は以下の定義をまず考えてみよう。
| 
(define greater
  (lambda (m n)
    (if (> m n) m n)))
(define list-max
  (lambda (lst)
    (if (null? (cdr lst))
        (car lst)
        (greater (car lst) (list-max (cdr lst))))))
 | 
以下の定義でも動作する。
ところで、関数型言語ならば、引数が同じ関数呼出しは同じ答えが得られるはずだから、無駄な計算は発生しない? ⇒ ダウト。その保証はない! 悩んでください。
| 
(define list-max
  (lambda (lst)
    (if (null? (cdr lst))
        (car lst)
        (if (> (car lst) (list-max (cdr lst)))
            (car lst)
            (list-max (cdr lst))))))
 | 
上記の例は、リストから値を抽出する関数であった。次にリストを返す関数を作ってみよう。
| 
(define my-append
  (lambda (lst1 lst2)
    (if (null? lst1)
        lst2
        (cons (car lst1) (my-append (cdr lst1) lst2)))))
 | 
実行方法: (my-append (list 1 2 3) (list 4 5 6))
予想結果: (1 2 3 4 5 6)
実行方法: (my-append (cons 1 (cons 2 ())) (cons 3 (cons 4 ())))
予想結果: (1 2 3 4)
| 
(define list-double
  (lambda (lst)
    (if (null? lst)
        ()              ← 空を表す。(list) と同じ。
        (cons (* 2 (car lst)) (list-double (cdr lst))))))
 | 
実行方法: (list-double (list 1 2 3 4 5))
予想結果: (2 4 6 8 10)
新しく作られるリストの各数値は、入力のリストの要素において隣り合う2つの数値の和とする。たとえば,(1 1) を入力すると (2) を返し、(1 2 1) を入力すると (3 3)を返す。
ただし、入力のリストの要素数が2未満のときは空のリストを返すこととする。
| 
(define add-next
  (lambda (lst)
    (if (< (length lst) 2)
        (list )
        (cons (+ (car lst) (car (cdr lst))) (add-next (cdr lst))))))
 | 
実行方法: (add-next (list 1 2 1))
予想結果: (3 3)
リスト操作と再帰呼出しに慣れるために、以下の関数を作ってみよう。できるところからやってみよう。
ヒント:1 つの問につき、関数を 2 つ作ると簡単。
よく使うプリンタの用紙は、A4サイズである(210mm x 297mm)。この用紙は、長辺を半分に折るとA5サイズの用紙になる(小数点の切り捨てはtruncate関数を使用)。A0サイズは、841mm x 1189mm という大きさである。では、nを変数として Anサイズの2辺の長さをペアの値で返す関数 (paper-a-size n) を定義せよ。
ヒント:ペアのデータ1を短辺、データ2を長辺とすることにする。
ヒント:ペアのデータを入力として、長辺を折り曲げて新しい短辺とし、短辺を新しい長辺としてペアの値を返す関数を作ってみる。
問題を説明する前に、次の式を見てみよう。
右辺の係数に注目すると、次の図のような関係が見えてくる。この図をパスカルの三角形という。
  
(a+b)の羃乗の数ごとに、係数をリストで表すと、次のようになる。
(a+b)nのときの係数のリストを返す関数 list-pascal(n) を定義せよ。
ヒント:list-pascal では、n = 1 のとき、「(list 1 1)を返すこと」として、そのほかのとき、「n - 1 の list-pascal の返り値について add-next を計算した結果の前後に 1 を付けたもの」とするとよい。つまり,n=3 の (1 3 3 1) を求める計算では、n=2 の list-pascal の返り値である (1 2 1) から、add-next を用いて (3 3) を求めて、前後に (1) を append すると実現できる。
できた人は、append を使わずに、cons を使って関数 list-pascal を定義しよう。
(注意:add-next の使用は各自の自由である。)