連鎖性言語/名前付けの対象は値ではなくコードスタック型言語では、プログラムはワードとリテラルの並びです。リテラルは、エバリュエータに遭遇するとスタックにプッシュされます。ワードは、プリミティブかサブルーチンで、サブルーチンはそれ自体がワードとリテラルの並びです。 ワード間で受け渡しされる値 (いわゆる「パラメータ」) に名前はなく、言語によって直接参照されることもありません。値は、必要なだけ表現力を持たせた複雑なものにすることができます。Factor は、豊富なコレクション (配列、ハッシュテーブルなど) をサポートしているほか、名前付きスロットを備えたユーザー定義クラスもサポートしています。ただし、値自体に名前は付けられません。Lisp や Java のような言語と同様、Factor では少なくとも次のものには名前を付けます。
ただし、ワードのパラメータに名前は付けません。 プログラムはワードとリテラルが並んだものに過ぎず、ワードのリテラルのあらゆる並びは、新しいワードに「まとめる (factor out)」ことができるので、結局は値ではなく、操作に名前を付けることになります。そして、どのような繰り返しでも作ることができ、名前を付けることができます。このことの重要性はいくら強調しても足りないくらいです。適用型言語では、一まとまりのステートメントと式を新しい 1 つの関数にまとめることは時として困難です。そのようなことを行うには最低限、目的の式の中で自由変数を特定し、これらの変数を新しい関数に渡す関数呼び出しでその式を置き換える必要があります。しかし、目的のコードの断片がローカル変数への割り当てを行っている場合には、それが不可能なことがあり、その場合は内容の変化した値を何らかのデータ構造の形で戻す操作が必要になります。すべての新しい Java IDE には、こうしたプロセスを自動化する「抽出メソッド (メソッドの抽出)」コマンドが用意されています。スタック型言語では、「抽出メソッド」操作とは単にカット&ペーストに過ぎません。 スタック型言語でプログラミングすると、ほかのプログラミング言語では気付かなかった多くのパターンが明確に見えてきます。たとえば、ワードとワードのつながり、つまりデータフローが明らかになります。そしてワードとワードのつながりを作ることもできます。 次に示すのは、適用型言語でよくあるパターンを C ライクな疑似コードで記述したものです。 var x = ...; foo(x); bar(x); これがパターンであるとは思わないかもしれません。まして名前付けや抽象化などの対象とは考えないでしょう。Factor には、まさに上の操作をする [ foo ] [ bar ] bi これで、 値 ( もうひとつ、データフローのパターンを示しましょう。 var x = ...; bar(x,foo(x)); Factor では、これを dup foo bar これで、 今度は、インスタンス変数へのアクセスとメソッド呼び出しに var customer = ...; var price = customer.orders[0].price; Factor では、この種のコードはとても自然に記述されます。スタック上の最初のオブジェクトからスタートし、次にメンバにアクセスし (アクセス子はスタック上の値を 1 つ消費して 1 つ残します)、あとはパスの最後に到達するまで同じ操作を繰り返せばよいからです。したがって、 orders>> first price>> Factor では、名前の付いた では、上の例をさらに利用してみることにしましょう。たとえば、 中間的なオブジェクト (オーダーのリスト、最初のオーダー、価格、さらに var customer = ...; var orders = (customer == null ? null : customer.orders); var order = (orders == null ? null : orders[0]); var price = (order == null ? null : price); 1 行のコードが 4 行になり、新しいローカル変数を 3 つ使うことになりました。各ローカル変数は 2 回参照されていますが、このコードが実行された後で使われる可能性はまずありません。また、上のコードには繰り返しがあり、[javascript{(foo == null ? null : foo.bar)}] が 3 回出現しますが、これを抽象化することはできません。一般的に不完全なデータ、とりわけ
問題は、上の対応策のどれも満足のゆくものではない点です。いずれも、開発者に不必要な作業を強いるか、または非常に限られた特殊な問題を解決するためにその場しのぎの構文を追加して言語を複雑にしてしまいます。 Factor では、この例の場合、 dup [ orders>> ] when dup [ first ] when dup [ price>> ] when もしこのような記述をしばしば使うなら、新しいコンビネータを定義して MACRO: maybe ( quots -- ) [ '[ dup _ when ] ] map [ ] join ; このように定義してやると、上のコードは次のようにすっきりと記述できます。 { [ orders>> ] [ first ] [ price>> ] } maybe どうですか。「デザインパターン」などといったものを使う必要もなければ、言語に新しい構文を追加することもなく、また不必要なコードを記述する必要もないことを考えれば、かなり優れた解決策ではないでしょうか。これはスタック型言語の優れた面を示すごく基本的な例ですが、こうした例は決して少なくありません。スタック型言語を使うと、不要な作業をせずに済むのです。 This revision created on Tue, 1 Sep 2009 16:23:03 by Ashberk (Added elvis operator for groovy example) |
|
|
All content is © 2008 by its respective authors. By adding content to this wiki, you agree to release it under the BSD license. |
|