削除された内容 追加された内容
M編集の要約なし
M +syntax highlight, code
65 行
Schemeでは一貫して括弧の入れ子構造になっているのがおわかりになると思います。これがまさにSchemeの言語仕様がシンプルであるという所以です。Schemeではプログラムの実行を進めていくことを「評価」と呼びますが、これも簡単に言えば数式を変形して簡単にしていくことに似ています。たとえば、数学では次のように式を変形し、値を求めていきます。
 
<syntaxhighlight lang="scheme">
1 + ((4 - 2) + 1)
= 1 + (2 + 1)
= 1 + 3
= 4
</syntaxhighlight>
 
これ以上簡単にしようがない「4」が出てきた時点で変形は終了です。これで答えが求まりました。このような変形をSchemeで表せば次のようになります。
 
100 ⟶ 101行目:
===文字列リテラル===
 
文字列の値を記述する場合は、その文字列をダブルクォーテーション({{code|")}}で囲んで記述します。これを「文字列リテラル」といいます。これはソースコード上で数値や変数(後述)と区別するためであり、実際の評価にこのダブルクォーテーションが影響することはありません。たとえば、{{code|"古今"}}{{code|"東西"}}というふたつの文字列をつなげるとすると、{{code|"古今""東西"」なの}}ではなく{{code|"古今東西"}}となります。また、{{code|123}}は数値ですが{{code|"123"}}は文字列です。さらに、{{code|"Hello."」「}}{{code|"こんにちは。"}}なども文字列です。
 
特別な文字を表す表現もあります。たとえば改行は{{code|\n}}、タブ文字は{{code|\v}}、逆スラッシュは{{code|\\」で}}と入力します。また、これらの特別な文字は文字列リテラルの中では直接入力できません。つまり、{{code|"(改行)"}}と書くと構文エラーになります。
 
リテラルを評価すると、そのリテラルそのものが示す値を返します。{{code|1}}を評価すると{{code|1}}{{code|"こんにちは"}}を評価すると{{code|"こんにちは"}}がそのまま返ります。
"」(対応するダブルクォーテーションが違う行にある)と書くと構文エラーになります。
 
リテラルを評価すると、そのリテラルそのものが示す値を返します。「1」を評価すると「1」、「"こんにちは"」を評価すると「"こんにちは"」がそのまま返ります。
 
===文字リテラル===
 
単一の文字を表現するには文字リテラルを使います。これは{{code|#\}}に任意の一文字を続けて表記します。たとえば{{code|#\a}}{{code|a}}を表します。また、スペースを{{code|#\space}}、タブ文字を{{code|#\tab}}で表すなどでします。
これは文字列リテラルとは扱いが異なりますので注意してください。たとえば{{code|"a"}}{{code|#\a}}はどちらも画面に表示させると{{code|a}}ですが、を表しますが、それぞれ「'''一文字の'''文字列」と「文字」で異なるので注意してください。
 
===真偽値リテラル===
条件が真か偽かを表すのには真偽値型の値を使います。{{code|#t}}は真、{{code|#f}}は偽を表し、条件によって処理をわけるときなどに使います。ただし、{{code|#f}}以外のすべての値は真として扱われます。
 
==コメント==
ソースコード中には[[w:コメント (コンピュータ)|コメント]]と呼ばれる注釈を書くことができます。コメント部分はプログラムの評価に一切関与しません。Schemeでは{{code|;}}からその行末までがコメントです。
 
>(define hoge 10) ;ここがコメント
hoge
Wikipedia:サンドボックス#ここから下に書き込んでください。
 
注釈を書く用途のほか、プログラムの一部分を一時的に評価しないようにするためにも使われます。もし評価して欲しくない部分を単純に削除してしまうと、あとで戻そうと思ったときに書き直さなければならず手間がかかるからです。コメントにしておけば先頭のセミコロンを削除するだけで元に戻せます。このように評価して欲しくない部分をコメントにすることをコメントアウトと呼びます。
 
==手続き==
Schemeには「手続き」(procedure)という概念があります。これは幾つかの処理を行いその結果を返すまとまりで、[[w:数学]]における[[w:関数]]と非常に良く似ています。たとえば、数学では「f(x,y) = x + y のとき、 f(1,2) = 3である」などといいますよね。Schemeでは{{code|f(x,y) {{=}} x + y}}の部分を「手続きの定義」、{{code|f}}を「手続き」、手続きの評価に必要な値を受け取る{{code|x}}{{code|y}}を「仮引数」と呼びます。{{code|f(1,2)}}」の部分を「手続きの呼び出し」、{{code|1}}{{code|2}}のように手続きの評価に使われる値を「引数」、実行した結果である{{code|3}}を「返り値」といいます。
では、手続きの呼び出しを表現してみましょう(実は下記の手続きの解説には幾つか方便が含まれています。ですが、ここで詳細を解説すると難しくなりすぎるので、詳しくは後述します。手続きの定義は少し難しいので後回しにします)。
 
132 ⟶ 131行目:
===手続きの文法===
 
Schemeの手続きの呼び出しは{{code|(手続き名 引数1 引数2 ……)}}という文法です。手続き名は変数です。手続きがどんな引数を取るのかは手続きによって異なります。手続き名やそれぞれの引数の間はひとつ以上の[[w:空白文字|空白文字]]で区切らなければなりません。手続き名や引数の間に空白文字がないと、区切りが分からなくなってしまうからです。空白文字とは[[w:改行|改行]]、[[w:タブ文字|タブ文字]]、[[w:半角スペース|半角スペース]]の3つのいずれかです。この構文はどんな手続きでも同じです。Schemeのほとんどの手続きは、その引数が評価されてから手続きに渡されます。
 
手続き呼び出しの丸括弧は数学の優先順位を示す括弧とは異なり、省略'''できません'''。このため、数学のような乗算が加算に優先する、といった優先順位はSchemeには'''存在しません'''。この仕様は記号の優先順位を覚える必要がない反面、数式を煩雑にしがちで、Schemeらしい点でもあります。手続きの呼び出しが何重にもなると括弧の数を間違いやすいです。括弧は{{code|(}}{{code|)}}がきちんと対になっていなければなりませんから気をつけましょう。SchemeのようなLisp系の言語は括弧だらけになるから苦手、という人も少なくないです。
 
===実際に試してみる===
 
Schemeには加算をする手続き「+」が予め定義されています。さっきの構文にのっとると、数学での<math>1 + 2</math>はSchemeでは{{code|(+ 1 2)}}と表記されます。処理系で実行して試してみましょう。できたら<math>1 + 2</math>以外にも試してみましょう。引数の和が返ってくるはずです。
 
>(+ 1 2)
151 ⟶ 150行目:
-270.008408
 
なんだか変な構文だと思われるかもしれませんが、これらの構文は[[w:S式|S式]]と呼ばれ、Schemeの構文のシンプルな言語仕様を支えています。「S式」は前置記法と呼ばれるもののひとつで、手続き名にあたるものが先頭に来ます。「前置記法」があるなら「中置記法」「後置記法」もあり、C言語など数学のような{{code|1 + 2}}という感じの中置記法を使えるものもあります。C言語には3種類全ての記法が入り混じっていますが、SchemeなどのLisp系の言語は、あえて前置記法のみに絞ることで、シンプルな言語仕様を保っています。
 
===注意===
 
幾つか手続き呼び出しに関して気をつけておくことがあります。手続きには「手続き名」「引数の数」「引数の型」「返り値の型」などの要素を持っています。たとえば、幾つ引数をとるかは手続きごとに決められており、多すぎたり少なかったりすると実行したときに[[w:エラー]]になります。ただ、たまたま「+」は引数が幾つあってもよい手続きです。
また、手続きは引数の型が決まっています。たとえば、[[w:加算]]をする手続き{{code|+}}は文字列を引数に呼び出すとエラーです。
たまたま「+」は引数の順番を変えても同じ値が返ってきますが、ほとんどの手続きは引数はその順番に意味があります。たとえば、{{code|-}}は1つ目の引数の値から2つめ以降の引数の値を減算する手続きなので、{{code|(- 10 5)}}{{code|(- 5 10)}}の値は違います。
Schemeには予め幾つかの手続きが定義されており、ユーザは新たに手続きを定義することもできます。そのScheme処理系にどの手続きが用意されているか確かめるには、その処理系の[[w:ヘルプ]]と言語仕様を確認する必要があります。
 
168 ⟶ 167行目:
2005
 
変数yearには数{{code|2004}}が束縛されましたので、変数yearが評価されるとyearに束縛された値{{code|2004}}が返ります。手続き+は{{code|2004}}{{code|1}}の和{{code|2005}}を返します。今まで説明に使ってきた手続き+も、じつはインタプリタ起動と同時に+に加算をする手続きが束縛されていたから使えるのです。手続きも一種の値として扱えるため、defineで束縛することができるのです。また、何も束縛されていない変数を評価しようとするとエラーです。
 
==構文==
178 ⟶ 177行目:
year
 
下のdefineでは、yearはすでに2004が束縛されています。手続きは引数を評価してから渡すのですから、yearは2004を返すはずです。従って、{{code|(define year 1000)}}{{code|(define 2004 1000)}}になるはずではありませんか。2004は変数ではないので、束縛はできないはずです。いや、そもそも最初のdefineではyearには何も束縛されていませんでしたから、なにも束縛されていない変数yearが評価されてエラーになるはずです。これはどうしたことでしょうか。
 
実はSchemeには手続き呼び出しと同じような構文でありながら、引数を評価せずに受け取る手続き呼び出しとはまったく別の式も存在します。defineは引数(のように見える部分)は評価しないのです。defineは手続きではなく、定義を行う「構文」に分類されます。
185 ⟶ 184行目:
Schemeなど[[w:Lisp]]系の言語が何故これほどまでにシンプルな構文にこだわったかには訳があります。Schemeプログラムは「リスト」と呼ばれるツリー状の構造をとるようになっているのです。Lispが[[w:人工知能]]研究の分野に使われてきたのは、プログラム上でプログラムを組み立てるのが非常に容易だからです。
 
たとえば、{{code|(+ 1 (- 2 3))}}という式は、実は次のようなリストです。
 
[[画像:scheme.png]]
グレーの矩形は[[w:carcdr]]の二つの区画を持つ「ペア」と呼ばれるものです。car部はそのペアが持っている値、cdr部はその次の要素を格納していると捉えることができます。car部には別のペアを格納することができます。cdr部は次の要素を示しますが、リストの終端を示すには空リストを使います。図中では{{code|()}}で表されているのが空リストです。Lispプログラムはこの構造の繰り返しであり、このツリー構造を作り上げることでLispプログラムを作ることができるのです。{{code|car}}{{code|cdr}}{{code|set-car!}}{{code|set-cdr!}}{{code|list}}{{code|quote}}などの手続きを使えば、Schemeプログラムをそのままリストとして扱えます。実はペアを直接作成する専用の構文もあるのですが、知らなくても今のところは構わないので、ここでは割愛します。
 
==Schemeの重要な手続きや構文==
204 ⟶ 203行目:
 
consはペアを作る手続きです。
{{code|(cons 1 2)}} => ({{code|1 . 2)}}
 
このペアから無限に続くリストが作れます。リストの終わりを {{code|()}}という空リストで示すこととすれば、1 2 3と続くリストは
{{code|(cons 1 (cons 2 (cons 3 '())))}}と定義され、
例えば、1 2 3と続くリストは、
{{code|(cons 1 (cons 2 (cons 3 '())))}}定義表現されます。
(1 2 3)と表現されます。
特に、Schemeでは、リスト構造が根本であり、それは、リストは再帰的(recursive)に定義される構造だからです。
 
<syntaxhighlight lang="scheme">
(cons 1 2) => (1 . 2)
(car (cons 1 2)) => 1
218 ⟶ 217行目:
(car (cons 1 (cons 2 '()))) => 1
(cdr (cons 1 (cons 2 '()))) => (2)
</syntaxhighlight>
 
この例だけ見ると、リストの重要性は判らないかも知れません。やはり、リスト構造を使った再帰的プログラミングをしてみないとね
 
===四則演算===
234 ⟶ 233行目:
1010
 
表示できるのは、Schemeの処理系が受け付けるすべての S式です。数値、文字、文字列、クオートされたリストなど、何でも表示できます。ただし、関数は内部表現が処理系毎に異なることに注意して下さい。{{code|(display 10)}} の評価値は、未定義です。他の変数に束縛する意味はありません。複数の値を表示するとき、Scheme では以下のように書くことができます。
 
>(define x "Xvalue")
241 ⟶ 240行目:
newline
 
準引用により {{code|,}} が前に付くと、値が展開されます。それから
 
>(display 10 output-port)
255 ⟶ 254行目:
15
 
新たに定義した手続きは二つの引数をとり、その平均を返します。その手続きは変数averageに束縛しています。インタプリタは{{code|(average 10 20)}}を手続き呼び出しだと判断し呼び出しました。前述では手続き名には変数を記述すると解説しましたが、実際には手続きの値をとる式を書きます。averageには手続きが束縛されているため、リストの先頭に書くことができます。従って次のようなこともできます。
 
> ((lambda (x y) (/ (+ x y) 2)) 10 20)
292 ⟶ 291行目:
hoge ;quoteを使うと、変数は変数そのものを返す
 
特別な構文(Schemeの機能の「構文」ではなく、一般的な意味の構文)として、{{code|'(+ 1 2)}}と書くことができます。{{code|(quote (+ 1 2))}}まったく同じ意味ですが、字数が少なく見やすくなります。このように、書きやすさ、見やすさのために導入された構文を[[w:糖衣構文]](シンタックスシュガー, syntactic sugar, syntax sugar)といいます。
 
== 関連項目 ==