REBOL-Core User Manual Chap4/ja
From DocBase
Contents |
Chapter 4 - Expressions
REBOL/Core Users Guide Main Table of Contents Send Us Feedback
(Original: http://www.rebol.com/docs/core23/rebolcore-4.html )
(Translation ver. 0.3)
1. Overview
REBOLの第一のゴールは、あらゆるコンピュータシステムにまたがる通信手段の標準を打ち立てることだ。REBOLはどのような情報でも表現可能なシンプルで、直接的な手段、それは最適な柔軟性と、最小の文法を持った、そういう手段を提供する。例えば、次の行を試してみよう:
Sell 100 shares of "Acme" at $47.97 per share
この行は英語によく似ていて、あなたがこれを送る際には書き易いし、受け取った際には読み易い。 しかし、この行はREBOLにおいて正しい行なので、あなたのコンピュータはこれを理解し、指示されたとおりに動作する。(この行はREBOLの"方言(dialect)"であることに注意しよう。これは間接的に評価される。この概念の詳細は以下で紹介する。)
REBOLは、あなたとあなたのコンピュータの間での共通の言語を提供する。さらには、あなたのコンピュータがこの式を、あなたの株式ブローカーのコンピュータ(そこでもREBOLが動いているとする)に送れば、あなたの株式ブローカーのコンピュータは式を理解し、指示されたとおりに動作する。 つまり、REBOLはコンピュータの間での共通の言語を提供するのだ。 さらには、この行を無数のコンピュータに送り、そこで動作させることも可能だ。
次の行は、REBOLの式の別の例だ:
Reschedule exam for 2-January-1999 at 10:30
上の例に示した式は(また、別の方言(dialect)で書かれているが)、あなたの医師が入力し、送られて来たとしよう。あるいは、あなたの医師により実行されているアプリケーションから送られてきたものかもしれない。だが、それは問題ではない。 重要なのは、この式が、ハンドヘルドのデバイスであろうと、情報キオスクであろうと、あるいはあなたが使っているテレビコンソールであろうと、コンピュータの種類によらず動作するということだ。
上の例で示したあらゆるデータの値(数、文字列、価格(通貨)、データ、そして時刻)は、REBOLの形式として正しいものとして標準化されている。 ただし、ワードはその意味を伝える際に、特定の文脈に依存する。 sell、at、そしてreadのようなワードは、異なった文脈においては異なった意味を持つ。ワードは相対的な式なのだ ―それらの意味は文脈に依存している。
式は、2つの方法のうちのどちらか一方で処理される: REBOLのインタプリタで直接行なわれるか、あるいはREBOLスクリプトで間接的に行なわれるか。間接的に処理される式は、方言(dialect)と呼ばれる。 先の2つの例は方言(dialect)の例であり、スクリプトによって処理される。 次の例は方言(dialect)ではなく、REBOLインタプリタで直接処理される。
send master@rebol.com read http://www.rebol.com
この例では、sendおよびreadというワードは関数であり、REBOLインタプリタで処理される。
REBOLは、情報が直接的にインタープリトされるか、間接的になされるかによって区別している。その区別は情報がコードであるかデータであるかによるものではなく、それがどのように処理されるかによる。REBOLコードは、あるときにはデータとして扱われ、データがコードとして扱われることもある。つまり、伝統的な、コードとデータの間の区別は、REBOLにおいては曖昧なものだ。 情報がどのように処理されるかは、それがコードなのかデータなのかによって決められる。
2. Blocks (ブロック)
REBOLの式は、この概念に基づいている: あなたは値とワードをブロックとして組み合わせる。
スクリプトにおいては、ブロックは通常スクエアブラケットで囲まれる。 スクエアブラケットの間に書かれたものは何であれ、そのブロックの一部だ。 ブロックの内容が何行に亘ることも可能だし、その形式は完全に自由だ。 次の例はブロックの内容のいくつものフォーマッティングの仕方を示している:
[white red green blue yellow orange black]
["Spielberg" "Back to the Future" 1:56:20 MCA]
[
"Bill" billg@ms.dom #315-555-1234
"Steve" jobs@apl.dom #408-555-4321
"Ted" ted@gw2.dom #213-555-1010
]
sites: [
http://www.rebol.com [save %reb.html data]
http://www.cnn.com [print data]
ftp://www.amiga.com [send cs@org.foo data]
]
いくつかのブロックは、暗黙的にブロックとされるため、スクエアブラケットが不要だ。 例えば、REBOLスクリプトの場合、スクリプトの内容はブロックとして書かれるが、スクリプト全体に対応するブロックを囲むブラケットは必要ない。 スクリプトの外側のブロックのスクエアブラケットは、暗黙的に存在しているとして扱われる。コマンドプロンプトへ入力する式や、コンピュータ間で通信されるREBOLメッセージも同様だ―それらはいずれも暗黙のブロックとなっている。
ブロックについてのそれとは別の重要なアスペクトは、それらは付加的な情報を含むことだ。ブロックは、値の集まりを特定の順番に従ってひとまとめにする。 つまり、ブロックはシーケンスと同様にデータセットとしても使うことができる。 これについてのより詳細な記述は、Seriesの章に書いてある。
3. Values (値)
REBOLは、表現され、またあらゆるシステム間で交換される、組み込みの値の集合を提供する。値はREBOLの式を構成する基本的な要素だ。
3.1 Direct and Indirect Values
値は直接的あるいは間接的に表現される。
直接的に表現される値は、語彙的(辞書的)、あるいは文字通りに書かれるものとして既知のものである。
間接的に表現される値は、それが評価されるまで未知(不定)のものである。 none、true、そしてfalseという値は、いずれもそれらを表すワードが必要である。 これらの値は、それらの値を既知のものとするために評価が必要であるため、間接的に表現される。 これは、listやhash、関数、オブジェクトなどの、他の値についても同様である。
3.2 Datatypes of Values (値のデータ型)
あらゆるREBOLの値は、特定のデータ型に属する。値のデータ型は、次のような定義になる:
- 特定のデータ型の値が取りうる範囲。例えば、論理型は、trueあるいはfalseしか取れない。
- 実行される操作。例えば、あなたは2つの整数型の値を加算できるが、2つの論理型が値を加算することはできない。
- メモリに値が格納されるやり方。ある種のデータ型はメモリなどに直接格納されるが、それ以外の、例えば文字列型などは、間接的に格納される。
習慣により、それらを目立たせるために、REBOLのデータ型はエクスクラメーションマーク(!)をつけて書かれる。例えば:
integer! char! word! string!
<div style="background-color:#f0e090; border:thin solid black;"> データ型ワードは単なるワードである
データ型を表すのに使われるワードは、REBOLの他のワードと同じようなものである。 それらを表すのに使っている!には別段なにもマジックはない。 </div>
REBOLが用意するデータ型のすべてについての詳細は、Values Appendixを参照のこと。
4. Evaluating Expressions
式を評価するということは、値を計算するということだ。 REBOLはスクリプトを構成する式のseriesを評価し、結果を返すことにより、処理を行なう。 評価は、実行、処理、あるいはスクリプトの実行などとも呼ばれる。
評価はブロックに対して行なわれる。ブロックはコンソールから入力することも出来るし、スクリプトファイルから読み込むことも出来る。いずれにせよ、評価のプロセスは同じだ。
4.1 Evaluating Console Input (コンソール入力の評価)
スクリプトに書かれているどのような式であれ評価が可能だが、同様にREBOLプロンプトから入力の評価が可能だ。これにより、スクリプトに書かれるここの式をテストする簡単な方法が提供される。
例えば、あなたがコンソールプロンプトから次のような式を入力したとしよう:
>> 1 + 2
この式は評価され、次のような結果を返す:
== 3
<div style="background-color:#f0e090; border:thin solid black;"> コードの例について...
上の例において、コンソールプロンプト(>>)と結果表示(==)は、それらがコンソールでどのように現れるかの概念を示すためのものである。以下の例においては、プロンプトおよび結果の文字列は表示しない。しかし、あなたが、結果を確認するためにこれらの例をコンソールに入力すると考えることが出来る。 </div>
4.2 Evaluating Simple Values (単純な値の評価)
直接的に表現された値は既知であるため、それらは単にその値を返す。 例えば、あなたが次の行を入力したとしよう:
10:30
10:30という値が返って来る。これは、直接的に表現された値すべてに当てはまる。以下のものを含む:
integer 1234
decimal 12.34
string "REBOL world!"
time 13:47:02
date 30-June-1957
tuple 199.4.80.1
money $12.49
pair 100x200
char #"A"
binary #{ab82408b}
email info@rebol.com
issue #707-467-8000
tag <IMG SRC="xray.jpg">
file %xray.jpg
url http://www.rebol.com/
block [milk bread butter]
4.3 Evaluating Blocks (ブロックの評価)
通常、ブロックは評価されない。例えば、次のブロックを入力したとする:
[1 + 2]
すると、同じブロックが返って来る:
[1 + 2]
ブロックは評価されていない; 単にデータとして扱われている。
ブロックを評価するためには、do関数を、次の例のように使う:
do [1 + 2] 3
do関数は、評価の結果を返す。 上の例では、3という数値が返って来ている。
ブロックが複数の式を含んでいる場合、最後の式の結果だけが返って来る:
do [
1 + 2
3 + 4
]
7
この例では、両方の式が評価されているが、 3 + 4という式の結果だけが返って来ている。
if、loop、while、そして(foreachなどのいくつもの関数は、ブロックをその関数自身の一部として評価する。これらの関数はこの章の後のほうで詳細を述べているが、ここで少しだけ例を示しておこう:
if time > 12:30 [print "past noon"] past noon loop 4 [print "looping"] looping looping looping looping
これは重要なことだ: ブロックは関数によって明示的に評価されない限り、データとして扱われる。ある関数だけが(?)、それらの評価を引き起こす。
4.4 Reducing Blocks (ブロックのレデュース)
あなたがブロックを、doを使って評価する時、最後の式の値のみが結果として返される。しかし、ブロックに含まれるすべての式の値に返って来て欲しい時もあるだろう。ブロックに含まれるすべての式の結果を返すには、reduce関数を用いる。次の例では、ブロック内の両方の式の結果を返すために、reduceが使われている:
reduce [
1 + 2
3 + 4
]
[3 7]
上の例では、ブロックは、その評価結果にreduceされている。reduce関数は、ブロック内の複数の結果を返している。
reduce関数は、評価されて他の関数に送られるような式のブロックを作ることを可能にするため、重要だ。reduceはブロック内の各々の式を評価し、結果の式を新しいブロックに送り込む。その新しいブロックが、reduceの結果として返される。
printなどの、いくつかの関数が、それ自身の操作の一部としてreduceを使っている。次の例を見てみよう:
print [1 + 2 3 + 4] 3 7
次の例に示すように、rejoinや、reform、そしてremold関数も、それ自身の操作の一部としてreduceを使っている:
print rejoin [1 + 2 3 + 4] 37 print reform [1 + 2 3 + 4] 3 7 print remold [1 + 2 3 + 4] [3 7]
rejoin、reform、そしてremold関数は、それぞれjoin、form、そしてmold関数に基づいているが、それらのブロックを最初にレデュースする。
4.5 Evaluating Scripts (スクリプトの評価)
do関数は、スクリプト全体を評価するのにも使える。通常、doは、次の例のように、ブロックを評価する:
do [print "Hello!"] Hello!
しかし、doが、ブロックの代わりにファイル名を評価する場合、ファイルはブロックとしてインタプリタに読み込まれ、次の例のように評価される:
do %script.r
<div style="background-color:#f0e090; border:thin solid black;"> REBOLヘッダが必要
スクリプトファイルが評価されるには、適切なREBOLヘッダを含んでいなければならない。詳細は、Scripts Chapterを参照のこと。ヘッダは、ファイルにスクリプトが含まれており、ランダムなテキストではないことを示す。 </div>
4.6 Evaluating Strings (文字列の評価)
do関数は、文字列の中にある式を評価するのにも使える。例えば、次の式のように:
do "1 + 2" 3
3が結果として返って来ている。最初に、文字列はブロックに変換され、それからブロックが評価されている。
文字列の評価は時には便利であるが、必要な場合のみに行なわれるべきである。例えば、REBOLコンソールのラインプロセッサーを作るためには、次のような式を入力すればいい:
forever [probe do ask "=> "]
上の式は、=>というプロンプトを表示し、あなたが行を入力するのを待つ。それからテキストが評価され、その結果が表示される。(もちろん、スクリプトはエラーを出すかもしれないので、実際にはこんなに単純ではないが。)
必要でない場合、文字列の評価は一般的には良い方法ではない。 文字列の評価はブロックの評価よりも効率が悪く、文字列中のワードの文脈が未知(不定)だからだ。例えば、次の行を見てみよう:
do form ["1" "+" "2"]
これは、次のように入力するよりも非常に効率が悪い:
do [1 + 2]
REBOLのブロックは、文字列のように簡単に構築できるし、ブロックは評価が必要な式としてより適した式だ。
4.7 Evaluation Errors (評価エラー)
評価において、様々な原因でエラーが発生し得る。例えば、あなたが数値を0で除算しようとしたような場合、評価は停止し、そしてエラーが表示される。
100 / 0 ** Math Error: Attempt to divide by zero. ** Where: 100 / 0
一般的なエラーは、ワードが定義される前に、それを使おうとする場合だ:
size + 10 ** Script Error: size has no value. ** Where: size + 10
それ以外に一般的なエラーとしては、式の中の関数に適切な値を与え名なかった場合がある:
10 + [size] ** Script Error: Cannot use add on block! value. ** Where: 10 + [size]
場合によっては、エラーの原因は簡単には分からない。そのため、何がエラーを引き起こしているのかを知るために、色々と試してみる必要があるだろう。
5. Words (ワード)
式は値とワードから構成される。ワードは意味〔?〕を表現するために使われる。 あるワードは、ある概念や、あるいは特定の値を表現することが出来る。
この章の先の例では、指揮中においていくつかのワードが説明無しに使われていた。 例えば、doや、reduceや、try}が説明無しに使われていた。
ワードは直接的に表現されている値とはいくらか異なった方法で評価される。 ワードが評価される時、その値が検索され、評価され、そして結果を返す。 例えば、次のように入力したとしよう:
zero 0
0という値が返されている。ワードzeroは、数値である0として既に定義されている。 ワードが検索され、zeroが見つかり、そして返されている。
doやprintのようなワードは、検索され、それらの値が、単純な値ではなく、関数が見つかる。 このような場合、関数が評価され、関数の結果が返される。
5.1 Word Names (ワードの名前)
ワードは英字、数字、そして次の文字からなる:
? ! . ' + - * & | = _ ~
ワードは数字で始まってはならず、また、数値と解釈されうるようなものも駄目だ。 例えば、-1や+1は数値であって、ワードではない。
ワードの終わりは、スペース、改行、あるいは次に示す文字で区別される:
[ ] ( ) { } " : ; /
つまり、ブロックのブラケットはワードの一部ではない。 例えば、次のブロックは、testというワードを含んでいる:
[test]
以下の文字は、ワードの中に使ってはいけない。使った場合、解釈を間違うか、エラーを引き起こす:
@ # $ % ^ ,
ワードの長さに制限は無いが、改行を越えてワードを構成することは出来ない:
this-is-a-very-long-word-used-as-an-example
次の例は、ワードとして適切なものの例だ:
Copy print test number? time? date! image-files l'image ++ -- == +- ***** *new-line* left&right left|right
REBOLは大文字と小文字の区別をしない。次に示すワードは、同じワードとして扱われる:
blue Blue BLUE
〔The case of a word is preserved when it is printed. ワードの大文字、小文字は、表示の時のために保存されている。(?)〕
ワードは再利用できる。ワードの意味は、文脈に依存するので、異なる文脈でワードを再利用できる。 REBOLにはキーワードは存在しない。 あなたは、それがREBOLで既に定義されているものであろうと、どんなワードでも再利用できる。 例えば、あなたはあるワードを、REBOLインタプリタがそのワードを使うのとは違うやり方で使うことも出来る。
<div style="background-color:#f0e090; border:thin solid black;"> 適切なワードを選ぼう
あなたが使うワードは慎重に選ぼう。ワードは意味に関連付けられる。 もしもあなたが適切なワードを選べば、あなたや他の人にとって、あなたのスクリプトを理解するのが容易になる。 </div>
5.2 Word Usage (ワードのユセージ)
ワードは2つの使われ方をする: シンボルとして使われる場合と、変数として使われる場合だ。次のブロックでは、ワードは色についてのシンボルとして使われている。
[red green blue]
次の例を見よう:
print second [red green blue] green
ワードは、色の名前として使われている以外の意味は持っていない。 ブロックの中に書かれたワードは、それが評価されるまではシンボルとして扱われる。
ワードが評価されると、今度は変数として扱われる。 上の例では、printというワードと、secondというワードが変数であり、要求された処理を行なうネイティブ関数を保持している。
A word can be written in four ways to indicate how it is to be treated, as shown in Word Formats.
ワードは、それがどのように扱われるかを示す、4つの書き方で書くことができる。 詳細はWord Formatsを参照のこと。
| Format | What It Does |
|---|---|
| word | ワードを評価する。これは、ワードを書くのに一番自然で、一般的な方法だ。もしもワードが関数を保持していれば、それが評価される。そうでなければ、ワードの値が返される。 |
| word: | ワードの値を定義したり、ワードに値を設定する。これは新しい値を与える。値は、関数を含め、何でも構わない。詳細はSetting Wordsを参照のこと。 |
| :word | ワードの値を取得する。ただし、評価は行なわない。これは評価なしに関数や他のデータを参照するのに便利だ。詳細はGetting Wordsを参照のこと。 |
| 'word | ワードをシンボルとして扱い、評価はしない。ワードそれ自身が値だ。 |
5.3 Setting Words (ワードに値を設定する)
ワードにコロン(:)が続いた場合、値の定義や設定が行なわれる:
age: 42 lunch-time: 12:32 birthday: 20-March-1990 town: "Dodge City" test: %stuff.r
ワードにはどのような方の値でも設定可能だ。 上の例では、ワードは、整数、時刻、日付、文字列、そしてファイルという値が設定されている。 もっと複雑な型の値を設定することも可能だ。 例えば、次の例では、ワードはブロックや関数が値として設定されている:
towns: ["Ukiah" "Willits" "Mendocino"] code: [if age > 32 [print town]] say: func [item] [print item]
<div style="background-color:#f0e090; border:thin solid black;"> なぜこのようなやり方でワードに値を設定するのか
多くの言語において、ワードに値を設定するのには、次のように等号が使われている:
age = 42
REBOLにおいては、ワードはコロンを使って設定される。 その理由は重要だ。 〔It makes the set operation on words into a single lexical value.これは、ワードに対する設定操作を、単独の語彙的な値に置き換える。(?)〕設定操作の表現は、atomic(これ以上分割できない)なものである。
次の例を使って、2つのアプローチの違いを見てみよう。
print length? [age: 42] 2 print length? [age = 42] 3
REBOLはreflective〔(?)〕な言語であり、自分自身のコードを操作することが可能だ。 値を設定するこの方法は、ワード設定操作を単一の単位として簡単に操作するようなコードを、あなたが書くことを可能とする。
もちろん、等号(=)が比較のオペレータとして使われているという、別の理由もある。 </div>
ワードの定義をカスケードに書くことによって、複数のワードを一度に設定することも可能だ。 例えば、次のそれぞれのワードの値は42に設定される。
age: number: size: 42
set関数を使って、ワードに設定することも可能だ:
set 'time 10:30
この例では、timeというワードに、10:30を設定している。 timeというワードは、リテラル(シングルクオートを使って)として書かれており、それにより評価されることはない。
set関数でも、複数のワードに値を設定することが可能だ:
set [number num ten] 10
print [number num ten] 10 10 10
上の例では、ワードがブロックの中に書かれているため、クオートされる必要がないことに注意しよう。ブロックは評価されないのだ。 print関数により、おのおののワードが、整数10に設定されていることが分かる。
setに対して、値のブロックが与えられた場合、個々の値によって、対応するワードが設定される。 この例では、one, two, そしてthreeが、それぞれ1, 2, 3に設定される:
set [one two three] [1 2 3] print three 3 print [one two three] 1 2 3
ワードの設定についての詳細は、Value Appendix内の、Word sectionを参照すること。
5.4 Getting Words (ワードの値を取得する)
すでに定義されているワードの値を取得するには、ワードの前にコロン(:)を置けばいい。コロンが前置されたワードは、そのワードの値を取得する。ただし、その値が関数だったとしても、それ以上の評価は行なわない。 例えば、次の例を見てみよう:
drucken: :print
新しいワード、drucken (printに対応するドイツ語だ)が定義されている。 これはprintが行なうのと同じ関数を参照している。 これは、:printが、printの関数を、それを評価せずに返しているために可能になっている。
今や、druckenはprintと同じ関数として動作する。
drucken "test" test
printとdruckenの両方とも、同じ値が設定されている。その値は、表示を行なう関数だ。
これは、get関数を使っても実現できる。 リテラルなワードが与えられたとき、getは、その値を評価せずに返す。
stampa: get 'print stampa "test" test
あなたが、値が何であるかを評価なしに知りたいような場合、ワードの値を取得する能力もまた重要だ。 例えば、次の行のようにして、あなたはワードがネイティブな関数であるか否かを知ることが出来る:
print native? :if true
ここでは、getはifに対する関数を返している。 if関数は評価されておらず、そのままnative?という、ネイティブなデータ型であるかどうかを判定する関数に渡されている。 コロンが付けられていなければ、if関数は評価され、引数が与えられていないためにエラーが発生するだろう。
5.5 Literal Words (リテラルワード)
ワードとリテラルとして扱う能力は便利だ。 setとgetや、 それ以外にもvalue?やunsetや、protectや、それにunprotectなどのような関数は、リテラルの値を要求する。
リテラルなワードは2つの方法の内の1つで書くことが出来る: ワードの前にシングルクオーテーションマーク(`)〔訳注: 原文ではバッククオートが括弧内に書かれているが?〕を前置するか(これはティックとして知られている)、ワードをブロックの中に書くかだ。
あなたは評価されるワードの前にティックを使うことが出来る:
word: 'this
上の例では、word変数はリテラルワードthisに設定され、thisの値に設定されるのではない。 word変数は、その名前を記号的に使う。 次の例では、あなたがwordの値を表示させようとしており、thisというワードを見ることになる:
print word this
あなたは、評価されていないブロックから、リテラルワードを得ることも出来る。次の例では、first関数は、ブロックの最初のワードを取り出して来ている。thisというワードは、その後にword変数に値として設定されている。
word: first [this and that]
どのようなワードも、リテラルとして使うことが出来る。 値を参照するかもしれず、参照しないかもしれない。 例えば、次の例では、hereというワードは値を持っていない。 printというワードは値を持っているが、リテラルワードは評価されないので、リテラルとして使うことも可能だ。
word: 'here print word here word: 'print print word print
次の例では、リテラルな値の重要性を紹介しよう:
video: [
title "Independence Day"
length 2:25:24
date 4/july/1996
]
print select video 'title
Independence Day
この例では、titleというワードがブロックの中から検索されている。 titleにティックが無ければ、その通常の値が使われる。 titleに通常の値が設定されていなければ、エラーが表示される。
リテラルについてのより詳細な情報は、Value AppendixのWord Sectionを参照のこと。
5.6 Unset Words (不定ワード)
値を持っていないワードは不定(unset)である。 不定なワードを評価しようとした場合、エラーが発生する:
>> outlook ** Script Error: outlook has no value. ** Where: outlook
この例において、エラーメッセージは、ワードに値が設定されていないことを示している。このワードは不定なのだ。 これを、noneに設定されている場合と混同しないように。 noneは適正な値なのだ。
すでに定義されているワードも、unsetを使って、アンセットすることが出来る:
unset 'word
ワードがアンセットされると、その値は失われる。
ワードに値が設定されているかどうかは、value?関数を使って知ることが出来る。この関数は、引数としてリテラルワードを取る:
if not value? 'word [print "word is not set"] word is not set
他のスクリプトを呼び出すようなスクリプト中において、ワードが設定されているかどうかを知ることが出来るのは便利だ。 例えば、あるスクリプトで、それ以前に設定されていないデフォルトのパラメータをセットすることがあるかもしれない:
if not value? 'test-mode [test-mode: on]
5.7 Protecting Words (ワードのプロテクト)
protect関数を使って、ワードに値が設定されるのを防ぐことが出来る:
protect 'word
保護されたワードに対する再設定を試みた場合、エラーが発生する:
word: "here" ** Script Error: Word word is protected, cannot modify. ** Where: word: "here"
unprotectを使って、ワードの保護を解除することも出来る:
unprotect 'word word: "here"
protect関数とunprotectは、ワードのブロックも受け付ける:
protect [this that other]
重要な関数とシステムワードは、protect-system関数を使って保護することが出来る。 関数とシステムワードを保護することは、初心者が重要なワードを間違って設定してしまいかねないような場合に便利だ。 protect-systemをあなたの user.r ファイルに書いておけば、すでに定義されているワードのすべてが保護される。
6. Conditional Evaluation (条件評価)
既に述べたように、ブロックは通常、評価されない。 ブロックの評価には、do関数を用いる必要がある。 ブロックを条件評価する必要がある場合もあるだろう。 以下のセクションでは、それを行なういくつかの方法を説明する。
6.1 Conditional Blocks (条件ブロック)
if関数は、2つの引数を取る。 最初の引数は条件であり、2つめの引数はブロックだ。 条件がtrueであれば、ブロックが評価され、それ以外の場合には評価されない。
if now/time > 12:00 [print "past noon"] past noon
条件は、普通は、その式を評価した結果がtrueかfalseになる;ただし、他の値を与えることも可能だ。 falseあるいはnoneという値だけが、ブロックが評価されるのを妨げる。それ以外のあらゆる値は(zeroも含めて)、trueであると扱われ、ブロックの評価が行なわれる。 これは、findや、selectや、next、そしてその他の、noneを買えす関数において、結果を確認するのに便利だ:
string: "let's talk about REBOL" if find string "talk" [print "found"] found
either関数は、if関数を拡張し、3つの引数を取るようにしたものだ。追加された3つめの引数は、条件がfalseの場合に評価される:
either now/time > 12:00 [
print "after lunch"
][
print "before lunch"
]
after lunch
either関数もまた、noneである値をfalseと同様に解釈する。
if関数も、either関数も、それらのブロックの評価の結果を返す。ifの場合、ブロックが評価された時だけブロックの値が返り、それ以外の場合はnoneが返る。 if関数は、変数の初期化を条件付きで行なう場合に便利だ:
flag: if time > 13:00 ["lunch eaten"] print flag lunch eaten
either関数の返り値の活用として、上の例を次のように書き換えてみよう:
print either now/time > 12:00 [
"after lunch"
][
"before lunch"
]
after lunch
ifも、eitherも、両方共関数であるので、それらのブロックの引数は、ブロック評価された時にブロック内で結果を出すようなものであれば、どのような式であっても構わない。 次の例を見てみよう。ifとeitherのブロック引数を表すために、ワードが使われている。
notice: [print "Wake up!"]
if now/time > 7:00 notice
Wake up!
notices: [
[print "It's past sunrise!"]
[print "It's past noon!"]
[print "It's past sunset!"]
]
if now/time > 12:00 second notices
It's past noon!
sleep: [print "Keep sleeping"]
either now/time > 7:00 notice sleep
Wake up!
ifの場合も、eitherの場合も、条件式が最初の引数として使われており、条件式は様々な比較関数と論理関数の組み合わせで書かれる。詳細は、Math Chapterを参照のこと。
<div style="background-color:#f0e090; border:thin solid black;">
よくやってしまうこの間違いを避けよう
REBOLにおいて、非常に一般的にやられる間違いは、eitherに対して2つめのブロックを付け忘れることと、 逆に、ifに対して2つめのブロックを付けてしまうことだ。 これらの例はどちらも、作者にとって見つけるのが難しいエラーになる:
either age > 10 [print "Older"] if age > 10 [print "Older"] [print "Younger"]
これらの類のエラーは見つけるのが難しいので、これらの関数が期待通りに動いていない様なら、このことを思い出して欲しい。 </div>
6.2 Any and All (どれかと、すべて)
any関数と、all}関数は、ある種の評価にショートカットを提供する。 これらの関数は様々な方法で使える: if}やeitherやその他の条件関数と合わせて、あるいは別個に。
any関数も、all関数も、評価の際に一編に評価される、式のブロックを受け付ける。 any関数は、最初に真となった式の結果を返し、 all関数は、最初に偽となった式の結果を返す。 偽となる式はnoneかもしれず、真となる式はfalseあるいはnone以外のあらゆる値であることをを覚えておこう。
any関数は、falseでない最初の値を返す。さもなければ、noneを返す。 all関数は、すべての式がfalseでない場合、最後の値を返す。さもなければ、noneを返す。
any関数も、all関数も、必要なもののみ評価を行なう。 例えば、anyが式の中で真となる値を見つければ、残りの式は評価されない。 anyを使った例を挙げよう:
size: 50
if any [size < 10 size > 90] [
print "Size is out of range."
]
anyの振る舞いは、デフォルトの値を設定するのに便利だ。 例えば、次のような行において、その値がnoneの場合にのみ値を100に設定する:
number: none print number: any [number 100] 100
同様に、様々な値を取り得る可能性があるならば、その内の最初の値(ただし、none以外の)を使える:
num1: num2: none num3: 80 print number: any [num1 num2 num3] 80
あなたは、anyを、findなどのような関数と一緒に使うことで,常に適正な結果を返すように出来る:
data: [123 456 789] print any [find data 432 999] 999
同様に、all関数は、すべての式の結果がtrueであることを要求するような条件に使える:
if all [size > 10 size < 90] [print "Size is in range"] Size is in range
あなたは、関数が評価される前に値が設定されているかどうかを確認することが出来る:
a: "REBOL/" b: none probe all [string? a string? b append a b] none b: "Core" probe all [string? a string? b append a b] REBOL/Core
6.3 Conditional Loops (条件付きループ)
until関数とwhile関数は、条件が適合するまでの間、ブロックの評価を繰り返す。
until関数は、ブロックがtrueを返すまで(つまり、falseやnoneではないということだ)、ブロックを評価する。 評価対象のブロックは、常に、最低一度は評価される。 until関数は、そのブロックの値を返す。
次の例は、colorブロックの中のそれぞれのワードを表示する。 ブロックは、colorブロックの最初のワードを表示することで始まる。 それから、次のcolorに・・・と、ブロック内のそれぞれのcolorに移っていく。 tail?関数は、ブロックの最後かどうかを確認し、 もしtrueが返れば、until関数を終了する。
color: [red green blue]
until [
print first color
tail? color: next color
]
red
green
blue
break関数は、untilループを脱出したい時に使う。
while関数は、2つの引数と取り、1つめのブロックがtrueを返す間、評価を繰り返す。 最初のブロックは条件ブロックであり、2つめのブロックが評価ブロックである。 条件ブロックがfalseか、noneを返すと、式ブロックは評価されず、ループは終了する。
先に示したものと似た例を、ここで挙げよう。 whileループは、表示すべきcolorが残っている場合に限りループを継続する。
color: [red green blue]
while [not tail? color] [
print first color
color: next color
]
red
green
blue
条件ブロックは、いくつの式を含んでいても構わないが、最後の式が条件を返す。 これを説明するために、次の例では条件ブロックにprintを追加してある。 これは、colorの値のインデックスを表示する。 つまり、ループの条件に使われている、colorブロックの最後かどうかを確認できる。
color: [red green blue]
while [
print index? color
not tail? color
][
print first color
color: next color
]
1
red
2
green
3
blue
4
ブロックの最後の値は、while関数から返されている。
breakを、ループを抜け出すために、いつでも使える。
6.4 Common Mistakes (よくある間違い)
条件式は、それらがfalseかnoneを返す場合のみに偽となり、それ以外の値を返す場合には真となる。 以下の例におけるすべての条件式は、0や空ブロックの場合でさえ、trueを返す。
if true [print "yep"] yep if 1 [print "yep"] yep if 0 [print "yep"] yep if [] [print "yep"] yep
次の条件式はfalseを返す:
if false [print "yep"] if none [print "yep"]
条件式をブロックとして囲ってはいけない。 ブロックに囲まれた条件式は、常にtrueを返す:
if [false] [print "yep"] yep
eitherとifを間違えないように。 例えば、あなたが次のように書こうとしたとしよう:
either some-condition [a: 1] [b: 2]
しかし、実際にはこのように書いてしまったとしよう:
if some-condition [a: 1] [b: 2]
if関数は、2つめのブロックを無視する。 これはエラーを引き起こすことは無いが、2つめのブロックは永遠に評価されることは無い。
逆もまた真である。 あなたが2つめのブロックを書き落として、次のように入力したとしよう:
either some-condition [a: 1]
either関数は正しいコードを評価することはなく、おそらく誤った結果を生み出すだろう。
7. Repeated Evaluation (繰り返し評価)
上で紹介したwhile関数と、until関数は、条件が合うまで〔訳注:untilの場合のみ?〕ループするために使われていた。 それ以外にも、特定回数のみループを行なう関数が用意されている。
7.1 Loop
loop関数は、指定された回数だけブロックを評価する。 次の例では、40個のダッシュからなる行を表示する:
loop 40 [prin "-"] ----------------------------------------
prin関数はprint関数に似ているが、引数を改行せずに表示する点が異なることに気をつけよう。
loop関数は、ブロック中で最後に評価された値を返す:
i: 0 print loop 40 [i: i + 10] 400
7.2 Repeat
repeat関数は、ループカウンタを監視できるようにloopを拡張したものだ。 repeat関数の最初の引数は、値のカウントを保持するために使われるワードだ:
repeat count 3 [print ["count:" count]] count: 1 count: 2 count: 3
最後のブロックの値が、やはり返される:
i: 0 print repeat count 10 [i: i + count] 55
先の例では、ワードcountは、ブロックの中でのみ値を持っていた。言い換えれば、countの値は、ブロック内で局所的だ。 repeatが終了すれば、countは、何であれ以前に設定された値を返す。
7.3 For
for関数は、開始時の値、終了時の値、そして加算していく数の指定を許可するようにrepeatを拡張したものだ。 いずれの値も、正の数であっても負の数であっても構わない。
次の例では、0から始まり、50まで、ループのたびに10ずつ加算していく。
for count 0 50 10 [print count] 0 10 20 30 40 50
for関数はループを行ない、最後の値を〔保持している(?)〕。 しかし、もしもカウントが終了時の値を超えた場合、ループはやはり終了する。 次の例では、終了時の値を55にした例だ。 この値は、ループごとに加算される値が10であるため、条件にヒットしない。 だが、ループは50で止まっている。
for count 0 55 10 [prin [count " "]] 0 10 20 30 40 50
次の例はカウントダウンを行なう例だ。 この例は4で始まり、一回に1ずつカウントダウンして、0まで行く。
for count 4 0 -1 [print count] 4 3 2 1 0
for関数は、小数を含む10進数、金額、時間、日付、series、そして文字についても同様に機能する。 開始時の値と終了時の値が同じデータ型であることを確認しよう。 次に、その他のデータ型を使ったループのいくつかの例を挙げよう。
for count 10.5 0.0 -1 [prin [count " "]] 10.5 9.5 8.5 7.5 6.5 5.5 4.5 3.5 2.5 1.5 0.5 for money $0.00 $1.00 $0.25 [prin [money " "]] $0.00 $0.25 $0.50 $0.75 $1.00 for time 10:00 12:00 0:20 [prin [time " "]] 10:00 10:20 10:40 11:00 11:20 11:40 12:00 for date 1-jan-2000 4-jan-2000 1 [prin [date " "]] 1-Jan-2000 2-Jan-2000 3-Jan-2000 4-Jan-2000 for char #"a" #"z" 1 [prin char] abcdefghijklmnopqrstuvwxyz
for関数は、seriesについても同様に機能する。 次の例は、forに対して、文字列の値を使った例だ。 darkというワードがdという文字の現在の位置を伴った文字列として定義されている。 for関数は文字列seriesを一文字ごとに移動し、endとして定義されている位置まで来ると、停止する:
str: "abcdef" end: find str "d" for s str end 1 [print s] abcdef bcdef cdef def
7.4 Foreach
foreach関数は、ブロックの各seriesの要素を評価するような繰り返しに対して便利な方法を提供する。
次の例では、ブロック内の各々のワードが表示される:
colors: [red green blue] foreach color colors [print color] red green blue
次の例では、文字列の仲の各々の文字が表示される:
string: "REBOL" foreach char string [print char] R E B O L
次の例では、ディレクトリブロック内の各々のファイル名が表示される:
files: read %.
foreach file files [
if find file ".t" [print file]
]
file.txt
file2.txt
newfile.txt
output.txt
関連があるような値のグループをブロックが含んでいる場合、foreach関数はグループ内の値のすべてを同時に取り出すこともできる。 例えば、時刻、文字列、そして価格を含んだブロックがあるとしよう。 foreach関数にワードのグループによるブロックが与えられると、それぞれの値が取り出され、表示される。
movies: [
8:30 "Contact" $4.95
10:15 "Ghostbusters" $3.25
12:45 "Matrix" $4.25
]
foreach [time title price] movies [
print ["watch" title "at" time "for" price]
]
watch Contact at 8:30 for $4.95
watch Ghostbusters at 10:15 for $3.25
watch Matrix at 12:45 for $4.25
上の例では、foreachの値のブロックは、[time title price]という3つの値のブロックとして指定されており、movieから、ブロックの評価のたびに取り出される。
foreachの値を保持するための変数は、ブロックに対して局所的だ。 それらの値は、繰り返しが行なわれるブロックの中でのみ設定されている。 ループを抜けると、変数は、以前に設定された値を返す。
7.5 Forall and Forskip
foreachと同様に、forall関数はseriesによるここの値からなるブロックを評価する。 しあkし、重要な違いがある。 foreall関数は、ループの開始時にseriesとして受け取る。 ループが進に連れ、foreallはseries内の位置を修正する。
colors: [red green blue] forall colors [print first colors] red green blue
上の例では、ブロックの評価の後で、seriesはその位置を次の位置に進めている。 foreallが返る時、colorのインデクスはseriesの最後になっている。
seriesを使って続けるためには、あなたは次のように頭の位置に戻してやる必要がある:
colors: head colors
forskip関数は、series内の値のグループからなるブロックを評価する。 forskipの2つめの引数は、各ループの後にいくつのエレメントを進めるかのカウントだ。
forallと同様に、forskipは、処理の開始時にseriesのインデックスと共にseriesを受け取る。 その後、forskipはインデックスの位置を、ループの進行に伴って修正する。 ボディーブロックの評価が終了した後に、seriesのインデクスは指定された数だけ進められ、次の位置を示す。 次の例はforskipのデモだ:
movies: [
8:30 "Contact" $4.95
10:15 "Ghostbusters" $3.25
12:45 "Matrix" $4.25
]
forskip movies 3 [print second movies]
Contact
Ghostbusters
Matrix
上の例では、forskipは、最後にmoviesを伴って実行されている。 seriesの位置を頭に戻すには、head関数を使わなければならない。
7.6 Forever
forever関数は、ブロックを永遠に、あるいはbreak関数に遭遇するまで評価する。
次の例では、10分ごとに、ファイルが存在しているかどうかを確認するためにforeverを使っている:
forever [
if exists? %datafile [break]
wait 0:10
]
7.7 Break
あなたは、break関数を使うことで、ブロックの繰り返し評価を停止させることが出来る。 break関数は、特殊な条件に遭遇し、ループを終了しなければならないような時に便利だ。 break関数は、すべてのタイプのループで機能する。
次の例では、数が5より大きくなった場合にループがbreakされている。
repeat count 10 [
if (random count) > 5 [break]
print "testing"
]
testing
testing
testing
break}関数は、/return 〔細分(単に「指定」? or 修飾?)(refinement)〕が使われない限り、ループからの脱出の際には値を返さない:
print repeat count 10 [
if (random count) > 5 [break/return "stop here"]
print "testing"
"normal exit"
]
testing
testing
testing
stop here
上の例では、条件が発生せずにrepeatが終了すれば、ブロックは文字列を返して、通常どおりに終了する。 そうでなければ、break/returnがstopという文字列を返す。
8. Selective Evaluation
REBOLには、式の選択的評価を行なう方法が存在する。 これらの方法は分岐が発生するような評価に対して、いろいろな方法を提供する。 これらの方法はkeyの値に基づいている。
8.1 Select
select関数は、対象となる値を与えられ、特定の値やブロックを取得するために使われたりする。 もし、あなたが値のブロックとアクションを定義すれば、あなたはある値に対応するアクションを見つけ出すのにselectを使える。
cases: [
center [print "center"]
right [print "right"]
left [print "left"]
]
action: select cases 'right
if action [do action]
right
上の例では、select関数は、rightというワードを見付け、そのワードに続くブロックを返している。 (何らかの理由でブロックが見つからなければ、noneが返るはずだ。) その後にブロックが評価される。 この例で使われた値はワードだが、どのような値でもか舞わない:
cases: [
5:00 [print "everywhere"]
10:30 [print "here"]
18:45 [print "there"]
]
action: select cases 10:30
if action [do action]
here
8.2 Switch
select関数は、switchと呼ばれるものの特殊な場合として使われる。 switch関数は、結果のブロックの評価まで含んでいる。 switch関数は、インラインの選択的評価の実行を簡単にしている。 例えば、単純な数値の場合にswitchを行なうとこうなる:
switch 22 [
11 [print "here"]
22 [print "there"]
]
there
switch関数は、評価するブロックの値を返すことも出来る。なので、上の例はこの様にも書ける:
str: copy "right "
print switch 22 [
11 [join str "here"]
22 [join str "there"]
]
right there
そして:
car: pick [Ford Chevy Dodge] random 3
print switch car [
Ford [351 * 1.4]
Chevy [454 * 5.3]
Dodge [154 * 3.5]
]
2406.2
場合は、適正なデータ型であれば、数値、文字列、ワード、日付、時刻、url、fileを含め、何でも構わない。 いくつか例を挙げよう:
文字列の場合:
person: "kid"
switch person [
"dad" [print "here"]
"mom" [print "there"]
"kid" [print "everywhere"]
]
everywhere
ワードの場合:
person: 'kid
switch person [
dad [print "here"]
mom [print "there"]
kid [print "everywhere"]
]
everywhere
データ型の場合:
person: 123
switch type?/word [
string! [print "a string"]
binary! [print "a binary"]
integer! [print "an integer number"]
decimal! [print "a decimal number"]
]
an integer number
ファイルの場合:
file: %rebol.r
switch file [
%user.r [print "here"]
%rebol.r [print "everywhere"]
%file.r [print "there"]
]
everywhere
URLの場合:
url: ftp://ftp.rebol.org switch url [ http://www.rebol.com [print "here"] http://www.cnet.com [print "there"] ftp://ftp.rebol.org [print "everywhere"] ] everywhere
タグの場合:
tag: <LI>
print switch tag [
<PRE> ["Preformatted text"]
<TITLE> ["Page title"]
<LI> ["Bulleted list item"]
]
Bulleted list item
時刻の場合:
time: 12:30
switch time [
8:00 [send wendy@domain.dom "Hey, get up"]
12:30 [send cindy@rebol.dom "Join me for lunch."]
16:00 [send group@every.dom "Dinner anyone?"]
]
8.2.1 Default Case
他の場合にマッチしなかった場合のために、デフォルトの場合を指定することも出来る。 デフォルトを指定するためには、default〔細分(指定? 修飾?)(refinement)〕を使う:
time: 7:00
switch/default time [
5:00 [print "everywhere"]
10:30 [print "here"]
18:45 [print "there"]
] [print "nowhere"]
nowhere
8.2.2 Common Cases
いくつかの値が同じ結果になる共通の場合があるなら、あなたは、コードの共通ブロックを保持するワードを定義することで対応できる:
case1: [print length? url] ; the common block url: http://www.rebol.com switch url [ http://www.rebol.com case1 http://www.cnet.com [print "there"] ftp://ftp.rebol.org case1 ] 20
8.2.3 Other Cases
ブロックが場合に応じて評価されるだけではない。 この例では、曜日に対応したファイルが評価されている:
switch now/weekday [
1 %monday.r
5 %friday.r
6 %saturday.r
]
もし、金曜日だとすれば、friday.rが評価され、その結果がswitchから返ってくる。 この種の評価はURLに対しても機能する:
switch time [
8:30 ftp://ftp.rebol.org/wakeup.r
10:30 http://www.rebol.com/break.r
18:45 ftp://ftp.rebol.org/sleep.r
]
caseに対する場合はブロックで囲まれているか、あるいはswitch文以外の所で定義されたものであっても良い:
schedule: [
8:00 [send wendy@domain.dom "Hey, get up"]
12:30 [send cindy@dom.dom "Join me for lunch."]
16:00 [send group@every.dom "Dinner anyone?"]
]
switch 8:00 schedule
9. Stopping Evaluation (評価の停止)
スクリプトの評価は、エスケープキー(ESC)を押すことで、いつでも中断できる。 あるいは、halt関数やquit関数を使っても中断できる。
The halt function stops evaluation and returns you to the REBOL console prompt:
halt関数は評価を中止し、REBOLコンソールのプロンプトに戻る。
if time > 12:00 [halt]
quit関数は評価を中止し、REBOLインタプリタからも脱出する:
if error? try [print test] [quit]
10. Trying Blocks
あなたは、ブロックを評価したいのだが、エラーが起こきてしまう。 しかしあなたはスクリプトの残りの部分の評価を中断したくないという場合があるかもしれない。
例えば、割り算を実行していて、0除算が発生してもスクリプトに停止して欲しくないかもしれない。
try関数は、ブロックの評価中に発生したエラーをキャッチすることが可能だ。 こrはdoとほとんど同じものだ。 try関数は、通常、ブロックの結果を返す; しかし、エラーが発生した場合、代わりにエラーバリューを返す。
次の例では、0除算が発生した場合、エラーをtry関数に戻し、その箇所から評価を再開する。
for num 5 0 -1 [
if error? try [print 10 / num] [print "error"]
]
2
2.5
3.33333333333333
5
10
error
エラーハンドリングについては、Errors Appendixに詳細が書いてある。
Updated 11-Dec-2006 - Copyright REBOL Technologies - Formatted with MakeDoc2
- Translated 28-Ap4-2009
