「ほんとう」を、決める
値の種類が、増える日
ここまで、あなたの言語の世界に住む値は、数だけでした。1 + 2 も x = 10 も、出てくるのはぜんぶ数。今日、この言語ははじめて「はい」「いいえ」を覚えます。
これは「新しい記号がひとつ増える」のとは、重みのちがう出来事です。数とは別の、第二の値の種類が生まれる——専門用語では、型(type)が増えると言います。育った姿がこれです。
- 式くらべる >
- 数3
- 数2
③の欄に、true。数ではない値が、はじめてそこに現れました。1 + 2 > 4 や 2 * 5 == 10 にも書きかえて、観察してください。
気づいてほしいのはこれです。比較も、演算である。+ が2つの数を受け取って数を返すように、> は2つの数を受け取って真偽を返します。くらべる記号は6つ——== != < > <= >=。
評価器には、1行の追加
レッスン3で書いた evaluate を覚えていますか。「左右を畳んでから、最後の一手」——比較も、まったく同じ畳みかたです。新しいのは、返ってくる値の種類だけ。
// 真偽を返す演算を、評価器に教える
function evaluate(tree) {
if (tree.value !== undefined) {
return tree.value; // 葉っぱ:数はその数
}
const l = evaluate(tree.left);
const r = evaluate(tree.right);
if (tree.op === "+") return l + r;
if (tree.op === ">") return l > r; // ← 今日の追加は、これだけ
}
// 「1 + 2 > 4」の木(+のまとまりが、>の左の子)
const tree = {
op: ">",
left: { op: "+", left: { value: 1 }, right: { value: 2 } },
right: { value: 4 },
};
console.log(evaluate(tree));Ctrl+Enter でも実行できます
4 を 2 に変えると、答えが true に変わります。レッスン3の演習で「評価器にとって、かけ算の追加は1行」と知ったあなたなら、もう驚かないはずです——比較の追加も、評価器では1行でした。
正直に言っておくと、働かされるのは今回も工程②です。木を組む側には「> は + より浅いところに来る」という階層をひとつ足し、さらにこのあと登場する { } の読みかたも教える必要があります。
もしも、を実装する
コース1のレッスン4で、あなたは「もし」を使いました。今日は、それを作る側です。実験室で確かめてください——これは、あの気温のプログラムの、あなたの言語版です。
- プログラム
- 代入きおん =
- 数30
- 文もしも
- 条件
- 式くらべる >
- 名前きおん
- 数25
- 式くらべる >
- そのとき
- 代入おすすめ =
- 数1
- 代入おすすめ =
- ちがえば
- 代入おすすめ =
- 数2
- 代入おすすめ =
- 条件
- 名前おすすめ
- 代入きおん =
1行目を 10 に変えると、③の最後が 2 に変わります。なお、if文そのものは③に値を残しません——この言語は「値を見せるのは式と代入だけ」という設計です。
では、種明かしです。この実験室の評価器がif文を処理している部分は、(すこし整えると)こう書かれています。
const c = evaluate(stmt.cond); // ① 条件の式を畳んで、値にするif (typeof c !== "boolean") { throw new Error("条件は、true か false で答えられる式にしてください。"); // ② 真偽か、確かめる}if (c) runBlock(stmt.then); // ③ 真なら、thenの側だけelse if (stmt.else) runBlock(stmt.else); // ④ 偽なら、elseの側だけifの実装に、JavaScriptのifを使っている——ずるいと感じたでしょうか。でも思い出してください、+ の実装にもJavaScriptの + を使ってきました。土台の言語の力を借りて、新しい言語を立ち上げるのが、インタプリタという仕組みです。
コース1で「条件がうそのとき、{ } の中は読み飛ばされる」と学びました。その正体が、上の③④です。選ばれなかった側の runBlock を、呼ばない——木としては組まれているのに、評価が訪れない枝。「読み飛ばし」とは、評価器の不作為のことだったのです。
「1」は、真か
上のコードの②に、立ち止まってください。条件が真偽の値でなかったら、エラーにする——つまりこの言語は、「条件は true/false のみ」と決めたのです。実際に見てみましょう。
- 文もしも
- 条件
- 数1
- そのとき
- 数2
- 条件
条件は、true か false で答えられる式にしてください。例:x > 3 / x == 0
①②は何も困っていないのに、③が断る。「1は真か?」と聞かれて、この言語は「答えられません」と返す設計です。
ところが。コース1の終わりに出会ったJavaScriptに、同じ質問をしてみてください。
// JavaScriptに「1は真か?」と聞いてみる
if (1) console.log("JSは、1を真とみなしました");
// では、ほかの値は?
if (0) console.log("0は真"); else console.log("0は、偽あつかい");
if ("") console.log("空文字列は真"); else console.log("空文字列も、偽あつかい");
if ("にわ") console.log("中身のある文字列は、真あつかい");Ctrl+Enter でも実行できます
JavaScriptは 1 を「真っぽい(truthy)」として通します。0や空文字列は「偽っぽい(falsy)」。同じ質問に、2つの言語が逆の答えを返しました。
どちらが正しい、ではありません。寛容な設計には「0かどうかをいちいち x != 0 と書かなくていい」手軽さがあり、厳格な設計には「if x と書きまちがえた瞬間に教えてもらえる」早さがあります。Pythonは寛容の側、Javaは厳格の側——「何を真とするか」という真理の境界線すら、言語設計者が引いた線なのです。
⟡ よりみち:真偽の計算は、コンピュータより100年早い
コース1で名前の出たジョージ・ブールは、1854年に「真と偽は、数のように計算できる」と示しました。最初のプログラミング言語より、およそ100年早い発明です。それを電気のスイッチと結びつけたのが、1937年の21歳の大学院生クロード・シャノンの修士論文——今日あなたが書いた「真偽を返す演算」は、この2人の仕事の上に立っています。
くらべた結果は、くらべられない
もうひとつ、この言語が引いた線があります。数学のnoteには「10 ≦ x ≦ 20」と自然に書きますが——
まだ木になりません — くらべた結果を、さらにくらべることはできません。
くらべた結果を、さらにくらべることはできません。例:a < b < c とは書けません。
①は読めるのに、②が断ります。1 < 2 の結果は true であって数ではないので、それをさらに 3 とくらべる意味が定まらない——だからこの言語は、文法の段階できっぱり断る設計にしました。
実は、ここも設計の分岐点です。Pythonは 1 < 2 < 3 を数学どおり「1 < 2 かつ 2 < 3」と読む特別ルールを持っています。一方JavaScriptは黙って通しますが、意味は (1 < 2) < 3、つまり「true と3をくらべる」——だから 3 > 2 > 1 は、見た目に反して false になります。
断る、数学に寄りそう、別の意味で通す。同じ1行に、3つの言語が3つの答えを出しました。あなたの言語が選んだ「断る」は、3つのうちでいちばん不親切で、いちばん事故が少ない線です。
✎ 演習:範囲を、入れ子で見はる
「x が10以上20以下なら はんいない を1にする」プログラムを完成させてください。数学なら 10 <= x <= 20 の一行ですが、あなたの言語ではくらべた結果をさらにくらべられません。下のコードはいま、10以上しか確かめていません——20以下の見はりを足してください。x を 5・15・25 に変えて、0・1・0 と出れば完成です。
- プログラム
- 代入x =
- 数15
- 代入はんいない =
- 数0
- 文もしも
- 条件
- 式くらべる >=
- 名前x
- 数10
- 式くらべる >=
- そのとき
- 代入はんいない =
- 数1
- 代入はんいない =
- 条件
- 名前はんいない
- 代入x =
ヒント1(考え方)
関所を2つ並べる、と考えます。「10以上か」の関所を通れた者だけが、「20以下か」の関所に進む。両方を通れた者だけが、1になれる。コース1でやった「もしの中の、もし」を、今度は自分の言語でやるのです。
ヒント2(かたち)
いまある if の { } の中に、もうひとつ if を入れます。外側が x >= 10、内側が x <= 20。はんいない = 1 は、内側の { } に引っ越します。
こたえ(の一例)
x = 15 のあとを はんいない = 0 / if x >= 10 { if x <= 20 { はんいない = 1 } } / はんいない とします(実験室では改行を入れて書いてください)。5・15・25で 0・1・0、境界の10と20では 1 になるはずです。
内側にifを入れる代わりに、if x >= 10 のあとに else で0に戻す2段の書きかたを選んだ人もいるでしょう。形がこれと違っても、5・15・25 が 0・1・0 になっているなら、それはあなたの設計の正解です。
このレッスンで分かったこと
- 言語に第二の値の種類 true/false が増えた。比較は「真偽を返す演算」で、評価器への追加は1行
- ifの実装は「条件を畳む → 真偽か確かめる → 選ばれた側の
runBlockだけ呼ぶ」。「読み飛ばし」の正体は、呼ばれない枝 - 「1は真か?」への答えは言語ごとに違う。寛容にも厳格にも利点があり、真理の境界線すら設計の選択
a < b < cの扱いも分岐点——断る(この言語)、数学どおりに読む(Python)、別の意味で通す(JavaScript)