高校数学の窓過去問検索

Scheme入門 第6章 リストプロセッサー


Lisp という言語をご存知?Lisp は List processor の略らしいです。無理矢理な略し方ですね。どうかと思います。それはともかく、Scheme は Lisp から派生した言語です。Lisp の名前の由来でもあるリスト(※1)操作の機能は、Scheme にも受け継がれています。




リスト。何のリストでしょう。何のリストでも良いんですが、とりあえず適当な数値のリストを。リストは、値を並べて括弧で囲って書きます。例えば次のように書きます。




(78 80 100 95 66 72 98)




ところで、これを Scheme のプログラム内にそのまま書くと、インタプリタは手続き呼び出しだと思ってしまいます。つまり




(display "Hello")




といった Scheme の式も、ある種のリストなので(※2)、同じに見えてしまうわけです。括弧の中の最初にあるのが手続きの名前ですから、先程のリストだと78 という手続きを実行するのだと考えますが、そんな手続きは無いのでエラーです。






    procedure application: expected procedure, given: 78; arguments were: 80 100 95 66 72 98
    (訳)手続きの適用:計算式の引数として80 100 95 66 72 98、計算式の先頭に78が与えられていますが、計算式の先頭は手続きでないといけません。



そこで、第5章でシンボルを得るのに使ったクォートを、ここでも使います。リストの前にクォートを付けて




'(78 80 100 95 66 72 98)




と書けば、リストを得ることが出来ます。あぁ、display を忘れると、そのままでは何も表示されませんので、お忘れなく(※3)。




(display '(78 80 100 95 66 72 98))






いい加減面倒っちいので、そろそろ慣れてきたでしょうし、これ以降いちいち display を書かないことにします。その代わり 式 -> 結果 のように簡略化して書きます(※4)。




さて、リストを扱う手続きを一通り紹介します。まずは値がリストであるか判定する手続き list?




(list? '(78 80 100 95 66 72 98)) -> #t




リストの長さを調べる手続き length




(length '(78 80 100 95 66 72 98)) -> 7




リストを作る手続き make-list




(make-list 10 4) -> (4 4 4 4 4 4 4 4 4 4)




リストを逆順にする手続き reverse




(reverse '(78 80 100 95 66 72 98)) -> (98 72 66 95 100 80 78)




リストを連結する手続き append




(append '(78 80 100 95) '(66 72 98)) -> (78 80 100 95 66 72 98)




リストの指定位置の要素を取り出す手続き list-ref




(list-ref '(78 80 100 95 66 72 98) 4) -> 66




リストを作る手続きは make-list の他に list というのがあります。次のような使い方をします。




(define x 10)
(list 1 2 3 x)
-> (1 2 3 10)




クォートでやると、x がシンボルとして入ってしまいます。この2つの違いに気を付けましょう。




'(1 2 3 x) -> (1 2 3 x)




次のような例も。




(list 1 2 3 (+ 10 20)) -> (1 2 3 30)
'(1 2 3 (+ 10 20)) -> (1 2 3 (+ 10 20))




後者の奇妙なリストは、リストの中にリストを入れた例で、数値 1、数値 2、数値 3、リスト (+ 10 20) から成る長さ 4 のリストです。リスト (+ 10 20) は、シンボル +、数値 10、数値 20 から成る長さ3のリストです。リストはこのように何重にでも出来ます。リストの中のリストにまたリストを入れて、その中にもリストを・・・どうぞご自由に。




第6章・完




第7章へ





※1:リストとは、元々順序づけられたデータのことを言う。Scheme上でのデータ構造の一つ。
細かい話を言うと、「順序づけられた」とは言ってもコンピュータのメモリ上に順序通り値が格納されているわけではなく、C言語で言うポインタを使って「順序良く並んでいるように」見せかけているだけである。また、メモリの連続した領域にデータが格納されているワケでも無い。すべてポインタを用いたマジックである。
この辺の話は初学者にはあまり関係無いが、第7章が詳しい。
リストは,データを先頭から順番に読み込み、あるいは書き込む「シーケンシャルアクセス」で目的を達成する。この方法はデータの挿入と削除は高速かつ簡単な反面、データへのアクセスは遅くなる、と言う利点/欠点が共存する。
しかしながら、リストはとても柔軟で、その柔軟さがSchemeにパワーを与えているのだ。

※2:と言うか、本当に単なるリストである。Schemeには計算式としてのリストとデータとしてのリストとの間に本質的な差は無い。単に「計算結果を出したいリスト」と「計算結果を出したくない(または出来ない)リスト」の2つがあるだけだ。クオート(')は明示的にリストの「計算結果を出したくない」時に使うオマジナイである。

※3:実はこれは処理系依存の話。DrSchemeの場合は、特にdisplayを付けなくても構わない。



※4:前述の通り、DrSchemeに於いてはdisplay自体は使わなくて構わないし、むしろなるべくdisplayの多用は避けた方が無難だろう。それは悪いスタイルである。
と言うのも、C言語やBASICの場合、いわゆる「print文」が出力の鍵を握っている為、多用される傾向があるが、Scheme等の関数型言語、かつ「世界最古のインタプリタ」では、計算して何らかの値を返すのが「当たり前」なのだ。従って、特に余計な操作は必要としない。
不必要に計算式にdisplayを被せると、データ同士やSchemeで書かれたプログラム同士のやり取りが阻害される可能性が高いので、C言語やBASIC流の流儀であるprint(ないしはprintf)にあたるdisplayを多用する事はむしろ控えるべきである。









DrScheme






  1. DrScheme での Language Pack の選択

  2. Scheme の単純な式「(+ 3 2)」, 「(- 10 4)」

  3. Scheme の単純な式(括弧の入れ子)

  4. Scheme の単純な式 (DrScheme の定義ウインドウ)

  5. 関数 area-of-disk の定義と,関数適用

  6. 関数 area-of-disk,変数 PI の定義と,関数適用(1)

  7. 関数 area-of-disk,変数 PI の定義と,関数適用(2)


0 コメント: