GaucheでRDBプログラミング:Gaucheでメタプログラミング(3)(1/5 ページ)
Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう(編集部)
皆さま、明けましておめでとうございます。本年もよろしくお願いいたします。
さて、今回はGaucheを使って、より大きなプログラムを書いていきます。Lispプログラミングの例題として、パズルのような難しいアルゴリズムを使ったプログラムもありますが、多くの読者の方はリレーショナルデータベース(RDB)をベースにしたWebアプリケーションを作られていると思います。
そこで、今回と次回でWebアプリを書いてみたいと思います。今回はRDBプログラミングを中心に学んでいきます。
Gaucheのデータ型とオブジェクトシステム
今回の主題であるWebプログラミングに入る前に、少しGaucheの基本的な事柄について学んでおきます。
GaucheはLispであり、関数が主役となりますが、オブジェクト指向言語の特性も持っています。ここではGaucheのオブジェクト指向には深く入りませんが、RDBとのインターフェイスではたくさんのクラスが登場するので簡単に触れておきます。
Gaucheには数値、文字列、リストやベクターなどたくさんのデータ型があります。そして、それらすべてに対応するクラスがあり、データはそれらクラスのインスタンスです。GaucheのオブジェクトシステムはJavaなどと同様にスロット(slot)と呼ばれるインスタンス変数を持っています。
Gaucheのデータは、describeという関数でそのデータが所属するクラスやスロットの情報を調べることができます。また、describe関数はデバッグ時などによく使うのでdという名前も付いています。
gosh> (describe 123) 123 is an instance of class <integer> gosh> (d "abc") "abc" is an instance of class <string> gosh> (d car) #<subr car> is an instance of class <procedure> slots: required : 1 optional : #f locked : #t currying : #f info : "car" setter : #<subr set-car!>
老婆心ですが、クラス名は<>が付くまたは付けなければいけないルールがあるわけではなく、シンボルに使える任意の文字列が使えます。しかし、習慣としてクラス名は<>でくくっています。
クラスの定義、使い方については後半でまた説明します。
コレクションとイテレータ
GaucheはLispですのでリストが主役ですが、ベクター(配列)やハッシュなどのデータの集まりを扱うクラスもあり、それらを統一した操作で扱えるコレクションフレームワークというモジュールが用意されています。
JavaSEのAbstractCollectionクラスの下に動的な配列(Array)やハッシュ(HashMap)、リスト(LinkedList)クラスがあるのと似ていますね。
コレクションフレームワークでは、コレクションのすべての要素に対し同じ操作を行う、特定の条件のものを見つけるなどの関数を抽象化したイテレータが定義されています。
例えば、以下のfor-eachは第2引数で指定されたコレクションの各要素に対し、第1引数で指定した関数(処理)を実行します。この例では、リスト、ベクター、文字列に対してその要素を表示(print)する操作を行っています。ちなみに、#<undef>やtなどのfor-each関数自身の戻り値はあまり意味がありません。
gosh> (use gauche.collection) #<undef> gosh> (for-each print '(1 2 3)) 1 2 3 #<undef> gosh> (for-each print #(1 2 3)) 1 2 3 t gosh> (for-each print "abc") a b c t
次の例は、コレクションの全要素に対して指定された関数を適用し、その結果をリストで戻すmap関数です。また、ここではlambdaを使って無名関数で処理を定義しています。
gosh> (map (lambda(n) (+ n 1)) '(1 2 3)) (2 3 4) gosh> (map (lambda(n) (+ n 1)) #(1 2 3)) (2 3 4) gosh> (map (lambda(c) (integer->char (+ (char->integer c) 1))) "abc") (#\b #\c #\d)
mapの戻り値はいつでもリストですが、任意のコレクションを戻したい場合はmap-toを使います。
gosh> (map-to <vector> (lambda(n) (+ n 1)) #(1 2 3)) #(2 3 4) gosh> (map-to <string> (lambda(c) (integer->char (+ (char->integer c) 1))) "abc") "bcd"
Copyright © ITmedia, Inc. All Rights Reserved.