このページではプログラミングのまったくの初心者、もしくは他のプログラミング言語は知っているがSchemeについて知識がないかたを主な対象者として、Schemeプログラミングを素早く習得できるように解説していきます。
Scheme(スキーム)とはプログラミング言語のひとつです。
Schemeの最大の魅力はそのシンプルさにあります。おそらく(Brainf***などのジョーク言語を除けば)現存するあらゆる言語のなかでも最も言語仕様が小さい言語で、つまりはもっとも習得のしやすい言語であるといえます。また、実用にもじゅうぶん耐えうるだけの機能を持ち、プログラミングの楽しさを体験するにはまさにうってつけです。すでにC言語やPerlなどの他の言語を習得している方にとっても、プログラミングの理解を深める上で覚えておいて損はない言語です。
この項ではSchemeの知識がゼロの状態から、最低限必要なことだけを最短で理解できるように解説していきます。この項では基本的だがしかし本格的なプログラミングの概念を学び終えるのに、初学者の方でも半日とかからない分量にしています。
さあ、Schemeでプログラミングをあっという間に身に着けてしまいましょう！
Schemeは2015年現在に至るまで何度か改良が加えられ、Revised7 Report on the Algorithmic Language Scheme(R7RS)という仕様書がもっとも新しいものです。ここではR7RSに準じて説明していきます。仕様の詳細については外部リンクの項を参照してください。
プログラムを実行するには、その言語に対応した何らかの処理系(プログラムを処理するソフトウェア。ここではプログラムを実行するもののこと)が必要です。プログラムの構文解説に入る前に、自分でプログラムを入力して確かめることができるようにインタプリタの使い方を覚えましょう。フリーウェアとして公開されている処理系も多いので探してみましょう。処理系を探すには外部リンクの項も参照してください。
もし処理系のインストール作業が億劫であれば、Webブラウザ上でSchemeプログラムの実行を試せるサイトがあります。次の「[http://codepad.org/ codepad]」というサイトでは、(1)ページ左のオプションボタンから、「Scheme」を選択する (2)テキストボックスにプログラムを入力する、もしくはコピーアンドペーストする (3)「Submit」ボタンを押す という手順を踏むだけで処理系のインストール作業なしにSchemeの実行を試すことができます。この項目程度の内容であれば「Codepad」でもじゅうぶん事足ります。
ためしに「codepad」を使ってみましょう。「Scheme」を選んでからテキストボックスに「(display "Hello, World!")」と入力し、「Submit」ボタンを押すと次のような結果が表示されます。
このコードを実行したところ、「Hello, World!」という文字列が出力された、ということです。他のコードを試してみる場合、「(display "Hello, World!")」の「"Hello, World!"」の部分を表示したい値に置き換えてください。たとえば、「(display (+ 5 9))」を入力すると「14」が出力されます。
他のインタプリタの大まかな使い方を説明します(以下は「Codepad」の使いかたではありません)。Schemeの処理系が入手できたら、そのヘルプにしたがって起動してみましょう。たいていのインタプリタでは、起動すると「>」記号が表示されてユーザからの入力待ちになります。
 >
では、インタプリタに「(+ 1 2)」と入力してみましょう。たいていの対話式の処理系では改行すると実行します。
 >(+ 1 2)
 3
 >
「3」が表示され、再びユーザからの入力待ちになりましたね。Schemeプログラム「(+ 1 2)」の実行結果が「3」だったということです。プログラムを入力して改行すると、入力されたプログラムが実行され、次の行に先ほどのプログラムの実行結果が表示されます。これを繰り返してSchemeプログラミングを進めていきます。
プログラムとはおおまかに言えば命令と式の羅列です。数値計算の時にはまさに数式を書いていくのですが、プログラミング言語には、文字列から一部分を切り取ったり、リストからデータを取り出したりと、数値計算ではない式があります。下図を見ればわかるように、数学で使われる数式の表現と対応するものが多くあります。数式に対応するものをSchemeで書けば、それがまさに数値計算をするプログラムになります。
Schemeでは一貫して括弧の入れ子構造になっているのがおわかりになると思います。これがまさにSchemeの言語仕様がシンプルであるという所以です。Schemeではプログラムの実行を進めていくことを「評価」と呼びますが、これも簡単に言えば数式を変形して簡単にしていくことに似ています。たとえば、数学では次のように式を変形し、値を求めていきます。
 1 + ((4 - 2) + 1) &= 1 + (2 + 1) \\
 &= 1 + 3 \\
 &= 4
\end{align}
これ以上簡単にしようがない「4」が出てきた時点で変形は終了です。これで答えが求まりました。このような変形をSchemeで表せば次のようになります。
 (+ 1 (+ (- 4 2) 1))
        ↓
 (+ 1 (+ 2       1))
        ↓
 (+ 1 3            )
        ↓
 4
数学の表記とは数字や記号の順番が異なりますが、何となく似た雰囲気はつかめると思います。入れ子になった括弧は、数学と同様に内側から評価してきます。プログラムといっても、数学の式を独特の表記で書き換えたようなものなのです。ただ、実際は式変形の途中経過は見せず、即座に「その式の値」つまり答えのみが出力されます。以下は実際の入力と出力の一例です。
 >(+ 1 (+ (- 4 2) 1))    ←入力(プログラム、式)
 4                       ←出力(答え、式の値)
この式を「codepad」で試すときは「(display (+ 1 (+ (- 4 2) 1)))」と入力してください(「display」はこの式の評価結果を表示させるという意味です。詳しくは後ほど解説します)。
このように評価して値を得ることを「値が返る(値を返す、値を戻す)」、返ってきた値を「返り値(戻り値)」などともいいます。ソースコード上でいえば、「値が返る」とは「ある式を評価し、その式の部分をその値で置き換える」ことだと考えるとわかりやすいかもしれません。
プログラムとは式そのものですから、ソースコードでは数字や文字列といったデータを記述していく必要があります。プログラミング言語にはそれぞれこのようなデータを書くための構文があり、このコード中に直接書かれた値を「リテラル」(literal)と呼びます。
ここでは最低限必要と思われるものだけ解説しますが、以下で紹介される以外にもいろいろな表現があります。詳しくは仕様を参照してください。また、以下の中にはまだ使い方が説明されていないものがありますが、それは後述します。
Schemeでソースコード中に数値を記述するには、そのまま半角数字で表記し、これを「数値リテラル」といいます。小数は小数点をピリオドで入力し、負の数を示すマイナス記号(-)も使えます。「2004」「3.14159265358979」「-273.15」などです。ただし、入力した数値が必ずしも入力したとおりの精度で扱われるとは限りません。頭に「#e」をつけ完全な精度で扱うことを指定することもできます。
数値型は、整数型integer、有理数型ratioral、実数型real、複素数型complexの構造を持っており、右のものは、すべての左のものを含みます。
なども文字列です。
と書くと構文エラーになります(エラーにならない処理系もあります)。
がそのまま返ります。
で表します。
ですが、それぞれ「一文字の文字列」と「文字」で異なるので注意してください。
以外のすべての値は真として扱われます。これを利用すると、失敗したり無効だったときは偽を返し、それ以外は何か別の型の値を返す、といった関数を実装できます。
式が真偽値型か調べるには、関数boolean?を利用します。
からその行末までがコメントです。
 >(define hoge 10) ;ここがコメント
 hoge
サンドボックス#ここから下に書き込んでください。
注釈を書く用途のほか、プログラムの一部分を一時的に評価しないようにするためにも使われます。もし評価して欲しくない部分を単純に削除してしまうと、あとで戻そうと思ったときに書き直さなければならず手間がかかるからです。コメントにしておけば先頭のセミコロンを削除するだけで元に戻せます。このように評価して欲しくない部分をコメントにすることをコメントアウトと呼びます。
を「返り値」といいます。
では、手続きの呼び出しを表現してみましょう(実は下記の手続きの解説には幾つか方便が含まれています。ですが、ここで詳細を解説すると難しくなりすぎるので、詳しくは後述します。手続きの定義は少し難しいので後回しにします)。
手続きはただ命令や数式の列をまとめる役目だけではありません。Schemeの豊富な機能は手続きを介して提供されているのです。また、あなたの書いたプログラムの機能を他のプログラムに公開するとき、それは手続きの定義によって行われます。Schemeの機能を呼び出すとは、用意された手続きを呼び出す構文を書くことと同義です。
という文法です。手続き名は変数です。手続きがどんな引数を取るのかは手続きによって異なります。手続き名やそれぞれの引数の間はひとつ以上の空白文字で区切らなければなりません。手続き名や引数の間に空白文字がないと、区切りが分からなくなってしまうからです。空白文字とは改行、タブ文字、半角スペースの3つのいずれかです。この構文はどんな手続きでも同じです。Schemeのほとんどの手続きは、その引数が評価されてから手続きに渡されます。
がきちんと対になっていなければなりませんから気をつけましょう。SchemeのようなLisp系の言語は括弧だらけになるから苦手、という人も少なくないです。
と表記されます。処理系で実行して試してみましょう。できたら1+2以外にも試してみましょう。引数の和が返ってくるはずです。
 >(+ 1 2)
 3
 >(+ 10 50)
 60
 >(+ 2004 2004)
 4008
 >(+ -25 10)
 -15
 >(+ 3.141592 -273.15)
 -270.008408
なんだか変な構文だと思われるかもしれませんが、これらの構文はS式と呼ばれ、Schemeの構文のシンプルな言語仕様を支えています。「S式」は前置記法と呼ばれるもののひとつで、手続き名にあたるものが先頭に来ます。
という感じの中置記法が中心ですが、3種類全ての記法が入り混じっています。これに対してSchemeでは、前置記法のみしか使わないシンプルな言語仕様になっています。
幾つか手続き呼び出しに関して気をつけておくことがあります。手続きには「手続き名」「引数の数」「引数の型」「返り値の型」などの要素を持っています。たとえば、幾つ引数をとるかは手続きごとに決められており、多すぎたり少なかったりすると実行したときにエラーになります。ただ、たまたま「+」は引数が幾つあってもよい手続きです。
は文字列を引数に呼び出すとエラーです。
の値は違います。
Schemeには予め幾つかの手続きが定義されており、ユーザは新たに手続きを定義することもできます。そのScheme処理系にどの手続きが用意されているか確かめるには、その処理系のヘルプと言語仕様を確認する必要があります。
束縛とは変数に値を関連付けることです。例を見てみましょう。手続きdefineは第一引数の変数に第2引数の値を束縛します。値が束縛された変数を評価すると、その変数に束縛された値が返ります。つまり、束縛された値を取得するには、単にその変数を書きます。
 >(define year 2004)
 year
 >(+ year 1)
 2005
を返します。今まで説明に使ってきた手続き+も、じつはインタプリタ起動と同時に+に加算をする手続きが束縛されていたから使えるのです。手続きも一種の値として扱えるため、defineで束縛することができるのです。また、何も束縛されていない変数を評価しようとするとエラーです。
上で束縛を説明しました。が、ここで疑問に思って欲しいことがあります。次の例を見てみましょう。
 >(define year 2004)
 year
 >(define year 1000)
 year
になるはずではありませんか。2004は変数ではないので、束縛はできないはずです。いや、そもそも最初のdefineではyearには何も束縛されていませんでしたから、なにも束縛されていない変数yearが評価されてエラーになるはずです。これはどうしたことでしょうか。
実はSchemeには手続き呼び出しと同じような構文でありながら、引数を評価せずに受け取る手続き呼び出しとはまったく別の式も存在します。defineは引数(のように見える部分)は評価しないのです。defineは手続きではなく、定義を行う「構文」に分類されます。
SchemeなどLisp系の言語が何故これほどまでにシンプルな構文にこだわったかには訳があります。Schemeプログラムは「リスト」と呼ばれるツリー状の構造をとるようになっているのです。Lispが人工知能研究の分野に使われてきたのは、プログラム上でプログラムを組み立てるのが非常に容易だからです。
という式は、実は次のようなリストです。
                   
などの手続きを使えば、Schemeプログラムをそのままリストとして扱えます。実はペアを直接作成する専用の構文もあるのですが、知らなくても今のところは構わないので、ここでは割愛します。
実は、以上で大まかな文法は説明し終わりました。Schemeの文法はほとんどS式なのです。まだまだ説明していない概念はいくらでもあるのですが、それらの機能はすべて手続きや構文で提供されるのです。たとえば、数値の大小を比較するのも手続きですし、文字列を表示するのもまた手続きです。GUIライブラリが提供されれば、ウィンドウを開いたりファイルを操作したり画像を表示したりするのもまた、手続きを介して行われます。
とはいえ、実際にあなたが望む機能を実現するには、どの手続きをどのように使えばいいのかわからないことでしょう。あとあなたに必要なのは、どんな手続きや構文が用意されているのか知り、具体的なプログラムを読んだり書いたりしてプログラミングの経験を積むことです。そのためには言語仕様を読めるようになる必要があります。ですが、以下でかんたんに主な手続きや構文を紹介しておこうかと思います。このほかにも有用なものがたくさんありますので、すべての機能を知るには言語仕様を参照しましょう。
Schemeの最も重要な手続きはペアをつくり、ペアから要素を
取り出す次の３つです。
consはペアを作る手続きです。
という空リストで示すこととすれば、1 2 3と続くリストは、
と定義され、
と表現されます。
特に、Schemeでは、リスト構造が根本であり、それは、リストは再帰的(recursive)に定義される構造だからです。
 (cons 1 2) => (1 . 2)
 (car (cons 1 2)) => 1
 (cdr (cons 1 2)) => 2
 (cons 1 (cons 2 '())) => (1 2)
 (car (cons 1 (cons 2 '()))) => 1
 (cdr (cons 1 (cons 2 '()))) => (2)
この例だけ見ると、リストの重要性は判らないかも知れません。
これらの四則演算の手続きは、整数や小数など数値型の値に適用できます。これだけでもSchemeを簡易電卓として使えそうですね。
displayは引数に与えられた値を出力します。プログラム実行中の途中経過を表示したりする場合にも便利です。下の例では結果が1010となっていますが、displayが表示した10とインタプリタがプログラムから得た値10が、改行していないのでつながって見えるだけです。文字列や変数も引数として使えます。
 >(display 10)
 1010
 の評価値は、未定義です。他の変数に束縛する意味はありません。複数の値を表示するとき、Scheme では以下のように書くことができます。
 >(define x "Xvalue")
 >(for-each display `(1 2 3 x ,x "\n" "newline"))
 1 2 3 x Xvalue
 newline
 が前に付くと、値が展開されます。それから
 >(display 10 output-port)
と書けば、出力先を変更できます。output-port は、関数 open-output-file の返り値を指定します。
lambdaは手続きを新たに定義し、その手続きを表す値を返す構文です。Schemeは手続きであっても、数値や文字列と同じように値として処理することができます。lambda構文の第一引数には手続きの引数名となる変数のリストを渡します。第2引数以降は手続き本体となる式を渡します。ここで作成された手続きは一種の値なので、defineで束縛することができます。サンプルプログラムを示します。
 > (define average (lambda (x y) (/ (+ x y) 2)))
 average
 > (average 10 20)
 15
を手続き呼び出しだと判断し呼び出しました。前述では手続き名には変数を記述すると解説しましたが、実際には手続きの値をとる式を書きます。averageには手続きが束縛されているため、リストの先頭に書くことができます。従って次のようなこともできます。
 > ((lambda (x y) (/ (+ x y) 2)) 10 20)
 15
平均を計算する無名の手続きを定義し、返り値をリストの先頭に使いその手続きを呼び出しています。
手続きは引数や返り値にも使えるため、手続きを返す手続きも作成できます。下の例では、最初に平均を計算する手続きを返す手続きを作成し、それを変数create-average-functionに束縛しています。そして、2つめ、3つめで変数create-average-functionに束縛されていた平均を計算する手続きをつくる手続きに、まず加算と乗算の定義を与え、平均を計算する手続きを得ます。そして、その手続きに引数10と20を与えて、具体的な平均値を計算しています。
> (define create-average-function 
     (lambda (add multiply) 
       (lambda (x y) (multiply (add x y) (/ 1 2)))))
 create-average-function
> ((create-average-function + *) 10 20) ; 相加平均
 15
> ((create-average-function * expt) 10 20) ; 相乗平均、exptは累乗を計算する組み込み関数。
 14.1421356...
quoteは引数に与えられたものを評価せずにそのまま返す構文です。
 >(quote (+ 1 2))
 (+ 1 2)		;(+ 1 2)は評価しないと(+ 1 2)というリスト
 >(define hoge 10)
 hoge
 >hoge
 10		;quoteを使わなければ、変数は束縛されている値を返す
 >(quote hoge) 
 hoge		;quoteを使うと、変数は変数そのものを返す
まったく同じ意味ですが、字数が少なく見やすくなります。このように、書きやすさ、見やすさのために導入された構文を糖衣構文(シンタックスシュガー)といいます。