言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

新しい EToys の設計

なぜか突然新しい EToys の設計について考えています。EToys とはデバッグ環境と実行環境の区別が無いシロウト向けのスクリプティング言語である。くらいの定義にしておきます。

EToys の特徴

新しい EToys が持つべき特徴について書きます。

  • Smalltalk 文に翻訳できる。
  • GUI での操作が基本だが、情報を失わずテキストで表現出来る。
  • 簡潔である。(ネストが無い。引数が一つしかない。)
  • 型を持つ(ドラッグアンドドロップに必要)。

テキスト表現

例えばぐるぐる回る車は次のように表現されます。メソッド定義の中では、Smalltalk とは別の文法が使われます。

"無名のオブジェクトを作ったら EToys グローバル変数に格納します。"
EToys at: #Car put: Player newInstance.
Car formNamed: '4649.png'.       "ペイントツールから自動生成"

Car method: #drive answers: Car. "返り値は車自身(インスタンス)だと定義、自動生成。"

"実装を定義。定義内でレシーバは書けない。最初のレシーバは Car 自体、
以降のレシーバは前のメッセージの返り値がそのまま使われる"
Car method: #drive for: [
  forward: 5.
  turnBy: 5.
].

method:for: によるメソッド定義の Smalltalk との違いは以下の通りです。これを見ると制限きつい感じですが、ようはスクリプトが画面に占める面積を狭くしたいのと、ドラッグドロップした時に不可能な組み合わせでくっつかないようになっています。

  • レシーバは記述出来ない。
  • レシーバは上の文の返り値(つまり、パイプのように振舞う)。最初の文のレシーバは自身(この場合 Car)。
  • 引数は一つ。
  • 定義された型以外の引数は記述出来ない。
  • メッセージの並びは型に制約される。
  • 最後の文の返り値がメソッドの返り値。

条件分岐

ネストできないのと、レシーバが書けないので、条件分岐は工夫が必要です。道路に沿って走る車です。

Car method: #drive answers: Car.
Car method: #drive for: [
  forward: 5.             "前に5歩進む。自分を返す"
  turnBy: nextDirection.  "nextDirection の返り値だけ回転。自分を返す"
].
"型にはクラスも書ける"
Car method: #nextDirection answers: Number.
Car method: #nextDirection for: [
  underColorNamed: '#FF0000'.   "車の赤い部分に重なっている色を返す"
  isColorNamed: '#FFFFFF'.      "調べた色は白でなら true を返す"
  ifTrue: [-10] ifFalse: [10].     "true なら -10 false なら 10 を返す"
].

colorUnder: と isColor: は二つで EToys の color:sees: に相当します。新 EToys では、車の下の色を他の用途にも使えるように二つのメソッドに分けます。ifTrue:ifFalse: は唯一二つの引数を持つメソッドです。

ネストが必要っぽい場所(この場合道の色で方向を変える所)では、必ず別のメソッドを記述しなくてはなりません。実際には GUI でネストしているように表示する事も可能ですが、メソッド名は必要です。このメソッド(nextDirection) は実行時ビューワに表示され、リアルタイムに値を表示します。つまり、デバッグに使用します。

ハンドルで回す

前述の通り、レシーバをスクリプトに書く事は出来ませんが変数だけを一行に置く事が出来ます。下の例では、Wheel と一行書くことにより、次の文のレシーバを設定しています。ネストは出来ないので、ハンドルの方向は別のメソッドで指定します。くどいですが、ネストが必要な場所では新しいメソッドが必要なはずであるという考えです。

"車とハンドルの定義"
EToys at: #Car put: Player newInstance.
Car formNamed: '4649.png'.
EToys at: #Wheel put: Plyaer newInstance.
Wheel formNamed: '5963.png'.

Car method: #drive answers: Car.
Car method: #drive for: [
  forward: 5.
  turnBy: handleHeading.
].

Car method: #handleHeading answers: Number.
Car method: #handleHeading for: [
	Wheel.    "レシーバを書くことは出来ないが、変数参照を一つだけ置ける"
	heading.  "ハンドルの方向を返す"
]

動機

現在の EToys は機能が貧弱な割りにあまりにも表現が複雑です。その原因としては、EToys が依然 Smalltalk の影響を強く受けすぎているからだと考えています。そこで、表現にあえて制限を加える事で使いやすい言語が出来ないだろうかと考えてみました。例えば、

  • ネスト出来ない (縦スクロールは我慢できるが横は醜いので)
  • レシーバを記述出来ない (コンテキストで大体決まってるだろう)
  • 引数は一つしか与えられない (横長禁止)
  • 型を記述しなくてはいけない (どうせ自動生成できる)

等の制限は、テキストのプログラムでは問題になりますが、GUI では利点になるという信念のもと、思考実験を続けています。