Erlang 基礎ポイント2 - プログラムの形式, 無名関数, パターン照合など
Erlangプログラムの形式
REPL環境でなく、ソースファイル(erlファイル)から実行するためには
以下の形式に従う。
-module(test). -export([func1/0,func3/1,func4/3]). func1() -> func2() + 5. func2() -> 3. func3(X) -> Y = X * 2, Y * 2. func4(plus, X, Y) -> X + Y; func4(minus, X, Y) -> X - Y; func4(_, _, _) -> "nothing". % コメント
まず、module文にモジュール名を書く。
モジュール名はソースコードを含んでいるファイル名(拡張子はerl)にする。
モジュールはErlangコードの基本単位だ。
export文には外部からアクセスを許容する関数名・引数の数を記述する。
Javaにおけるpublicといえば、分かりやすい。
コンマで区切って複数指定可能。
次はJavaのようにメンバー変数が来そうだが、そんなものはない。
すぐ処理ロジックを含む関数が来る。
関数のシグネチャにリターンタイプとか、引数の型の指定がない。
関数名と引数名だけを書いて、->の後、すぐ処理内容を記述する。
関数の処理内容は行ごとにコンマで区切って、関数の最後にピリオドを打つ。
引数の数が同じ関数を複数(いわゆる、オーバーロード)書く場合、
各関数の終わりにコンマでなくセミコロンを書く。
但し、最後の関数の終わりにはコンマを書く。
型のチェックは実行時に行われる。
つまり、Erlangは動的型付け言語である。
コメントは%の後に書く。
無名関数
Erlangでは関数を無名で宣言して、変数に代入したり関数の引数や戻り値として使用することができる。
1> F = fun(A) -> A * A end. #Fun<erl_eval.6.80247286> 2> F(2). 4 3> Y = F. #Fun<erl_eval.6.80247286> 4> Y(4). 16
funで始まって、end.(ピリオドがあることに注意)で終わる。
次は無名関数を関数の引数に渡したり、戻り値として返す例だ。
% 引数 9> F = fun(A) -> A * A end. #Fun<erl_eval.6.80247286> 10> lists:map(F, [1, 2, 3, 4]). [1,4,9,16] % 戻り値 12> Plus = fun(X) -> (fun(Y) -> X + Y end) end. #Fun<erl_eval.6.80247286> 13> PlusFive = Plus(5). #Fun<erl_eval.6.80247286> 14> PlusFive(9). 14
リスト内包表記
リストから特定条件を満たす要素で構成された新しいリストを作るためのErlangの機能。
普通、リストから特定要素を持つ新しいリストを作るためには
新しい空のリストを宣言しておいて、ループと条件文を利用し、
条件にマッチした要素を空のリストに入れる処理が必要なので、
コードが長くて読みづらくなる。
しかし、リスト内包表記を使うと、リスト(例 : [ 1, 2, 3])の中で
新しいリストを作るための専用の表記ができるので、コードが短くて
読みやすい。
1> L = [1, 2, 3]. [1, 2, 3] 2> [X - 1 || X <- L]. [0, 1, 2].
後ろの部分、X <- LはリストLから要素Xを取り出すという意味で、
"||"の左側に要素Xで行う式を書く。
レコード
Cにおける構造体のようなもの。
Erlangでレコードの宣言方法は色々あるが、よく使われる方法は
拡張子がhrlのファイルにレコードを定義し、
そのhrlファイルをerlファイルで
インクルードする方法だ。
% person.hrl -record(person, { name, age, tel = 000-0000-0000 }).
% test.erl -module(test). -export([duke/0]). -include("person.hrl"). #インクルード duke() -> #person{name=duke, age=34, tel="0800000-0000"}.
レコードの宣言は、まず、-recordキーワードを書いて、
1番目の引数にレコード名、次に要素名のタプルを指定する。
要素にはデフォルト値の指定ができる。
レコードの使用は
#レコード名{要素1=値, ... , 要素x=値}
のようにする。
パターン照合
Erlang 基礎ポイント1 - DukeLabでちょっとだけ、触れたが、ここでもうちょっと説明しよう。
Erlangで、=は代入するのではなく、パターン照合するという。
以下の場合、Aに100を代入するのではなく、右側(100)の評価結果と左側のパターン(A)を照合するのだ。
A = 100
上記の例だと、ぱっとイメージしにくいだろう。
パターン照合とイメージが似ているのは正規表現ではないかな。
正規表現を使うと、ある複雑な文字列からパターンにマッチする特定の部分を手軽に抽出することができる。
ただし、正規表現のルールが分かりにくい短所はある。
同じくErlangのパターン照合も正規表現のようなものだが、
文字列だけでなく、タプル、リスト、関数の引数など、何にでも使えると考えればいいだろう。
以下の例を見てみよう。
19> T = {{name, "duke"}, {age, 34}}. {{name,"duke"},{age,34}} 20> {{_,_},{_,MyAge}} = T. {{name,"duke"},{age,34}} 21> MyAge. 34
Tにタプルが二つ({name, "duke"}と{age, 34})が入っているが、
二つ目のタプルから年齢(34)を取得したい場合、20>のように
パターン照合すればいい。20>の左側にあるパターンのうち、
_(アンダーバー)はダミー要素で何でもマッチする。
マッチするだけで変数に束縛したくない場合、_(アンダーバー)を使う。
パターンのうち、大文字で始まっているMyAgeが
二つめのタプルにある2番めの要素(34)に一致して
年齢(34)を取り出せたことが分かる。
パターン照合の基本が分かれば、後はマニュアルか
ググってパターン照合の例を参考すればいいだろう。
最後に関数のパターン照合に関する例を載せる。
% func_test.erl -module(func_test). -export([add/2]). add(X,plus) -> X + X; add(X,pow) -> X * X; add(X,Y) -> X + Y + 1. % 以下はREPL環境で実行したもの。 1> c(func_test). {ok,func_test} 2> func_test:add(3, plus). 6 3> func_test:add(3, pow). 9 4> func_test:add(3, 5). 9 5> c(func_test). {ok,func_test}
ガード
ある関数を呼び出すと、呼び出される関数を探すため、
引数に指定した値の型と関数のシグネチャとのパターン照合を行う。
Javaのオーバーロードと似ているものだと考えればよさそう。
追加的にメソッド内で引数の値の内容によって、違う動作をする必要がある時、
Javaではif文やポリモーフィズムを使うが、Erlangではガードを使えばいい。
ここでは関数を中心にガードを使い方を説明するが、
case式やif式でも使用できる。
以下のソースを見てみよう。
% guard_module.erl -module(guard_module). -export([guard_test/1]). guard_test(X) when X < 5, X > 1 -> X * X; guard_test(X) when X >= 5; X < 10 -> X - 2; guard_test(X) -> X - 2.
上記のソースを解析してみると、
呼び出された関数がguard_testで一番目の引数(X)に値が指定されていて、
Xが5未満かつ1より大きければ(コンマ[,]はandを意味)、X * Xを、
Xが5以上か10未満なら(セミコロン[;]はorを意味)、X - 2を、
それ以外の場合(つまり、elseなら)、X - 2
を返すという意味だ。
以下は上記の関数をREPL環境でテストしたものだ。
1> c(guard_module). {ok,guard_module} 2> guard_module:guard_test(5). 3 3> guard_module:guard_test(1). -1 4> guard_module:guard_test(6). 4 5> guard_module:guard_test(15). 13 6>
ガードは条件文のようなものだと考えればいい。
ガードは便利そうだが、関数の宣言部が複雑になる恐れがあるので、
なるべくパターン照合だけで済ませた方がいいと思う。
今日はここまで。
Javascript 注意点
Javascriptを使うにあたって
注意すべきところをメモっておこう。
会社、家でJavascriptプログラミング時に
経験したのを書くつもりだ。
もちろん、全て汎用的な内容だし、本に書いてある内容も
あるはずだ。
-----------------------------------------------
1)オブジェクトリテラルで最後の要素の後にコンマをつけてはならない。
=> IE7でエラーになる。
例)var o = { name : "Duke", hobby : ["movie", "animation", "reading", ""] , // ここにコンマを入れちゃだめ!!};
hobbyの次にコンマを入れるとIE7でエラーになる。
IE8とFireFox、Chromeではコンマを入れても問題ないが、
世の中未だIE6を使う人がいる現実を考えると
コンマを抜く方が精神健康上、いいだろう。
2)配列の最後の要素の後にもコンマをつけてはいけない。
いけないというか、ブラウザ間の動作が違うので避けましょうとの話だ。
今回もIEが問題だ。バージョン関係なく(正確にはIE7とIE8)。
var a = [1, 2, ];
console.log(a.length);
// 結果
// IE7 : 3
// IE8 : 3
// Chrome : 2
// FireFox : 2
IEでは最後のコンマの後をundefined要素と見なしているようだ。
ChromeかFireFoxでは本当の要素のみを配列の要素と見なしているようだ。
とにかく、結果が一つになる文法を使おう。
配列の最後の要素の後にコンマを入れちゃアカン!
3)with文は使っちゃだめ。
ある意味すごく便利なキーワードだが、間違った動作を起こす恐れがある。
(Visual BasicのWith-End Wih文と同じ感じ)
単純に参照名の省略だけでなく、内部で参照オブジェクトの有無を判別する
分岐文など、余分のコードが実行される。
コスト的にも問題だが、with文の内部がおかしくなると、バグを探すのが
非常に難しくなるので、使うのはやめた方がいい。
例えば、以下のコードは
with (obj) {
a = b;
}
実際は以下のコードと同じ処理をする。
f (obj.a === undefined) {
a = obj.b === undefined ? b : obj.b;
} else {
obj.a = obj.b === undefined ? b : obj.b;
}
出典
JavaScript: The Good Parts: Working with the Shallow Grain of JavaScript
- 作者: Douglas Crockford
- 出版社/メーカー: Yahoo Press
- 発売日: 2008/12/17
- メディア: Kindle版
- この商品を含むブログを見る
これを見ると分かるように実際どの処理が行われるかを
すく知ることはできない。
よって、with文は避けた方がいい。
4)parseInt使用する時、2番目の引数に進数を指定しなければならない。
var str = "051";
var a = parseInt(str);
console.log(a);
さあ、何が表示されるか。
51?
ブー。
41が表示される。
なぜなら、parseIntにソース文字列が何進数かを指定しないと、
文字列表現を見て自動判別するからだ。
前に0がつくと、8進数と判断する。
前に0xがつくと、16進数と判断する。
例の051は前に0がついているので8進数の51と判断し、
それを10進数の41に変換したのだ。
こういう自動判別を防ぐためには2番目の
引数に進数を指定すればいい。
var str = "051";
var a = parseInt(str, 10); // "strは10進数です"と指定する。
console.log(a);
結果は正しく51になる。
私たちが普段外からもらう数字は10進数なので、
parseIntの2番目の引数には必ず10をつけるように
しよう。
5)==, !=の代わりに===、!==を使おう。
Javascriptで==と!=は互いのオペランドの型が違う場合、
強制に型変換が行われる。
便利な面もあるが、分かりにくいバグを出してしまう場合もある。
以下の例のように想像と全然違う結果を出してしまう。
1)'' == '0' // false
2)0 == '' // true
3)0 == '0' // true
4)false == '0' // true
5)' \t\r\n ' == 0 // true
===と!==は型の変換が行われず、実際型までチェックするので
安心だ。
6)より安全なクラス宣言の仕方 --- 7)を参照すること。
Javascriptでクラス宣言する方法は色々ある。
次にPersonというJavaクラスがある。
public class Person {
private final String name;
private final int age;
public Person(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() { return name;
}
public int getAge() {
return age;
}
}
上記のPersonクラスをJavascriptで書いてみると、
方法は色々あるが、二つだけ、挙げてみる。
1番目
var Person = function(name, age) {
this.name = name;
this.age = age;
};
Person.prototype = { // publicメソッド
getName : function() {
return this.name;
},
getAge : function() {
return this.age;
}
};
Personクラスの宣言とメンバーメソッドの宣言が分かれている。
長所 :
1)インスタンス生成時、prototypeに宣言されている内容を再利用するのでメモリ管理面で有利である。
短所 :
1)宣言部が分かれているので少々分かりにくい印象がある。
2)publicメソッドでprivateメソッドが呼べない。prototypeではthisで始まるメンバーしか呼べない。
2番目
var Person = function(name, age) {
this.name = name;
this.age = age;
// private field
var count = 0;
// private method
var getCalledCount = function() {
return count++;
}
// public method
this.getName = function() {
return this.name + " : " + getCalledCount();
};
this.getAge = function() {
return this.age;
};
};
長所:
1)宣言部が統合されているので分かりやすい(変数の使用スコープが把握しやすいので)。一般的なクラス宣言に近い。
2)publicメソッド内でprivateメソッドが呼べる。
長所:
1)インスタンス生成時(つまり、new時)、毎回メソッドを動的に生成するので遅い。
答えは出た。
Javascriptはプロトタイプ型OOP言語だが、まだprototypeに慣れていない人が多いので
無理して使っても、メンテナンスする人に文句ばかり言われるだろう。
で、2番目のような宣言方式を使えば無難ではないかと思われる。
速度の問題はあるが、これ以外の問題(間違ったJavascriptの使用を意味)がもっと多いはずなので、
別に問題にならないと思う。クライアントPCの性能もよくなったし。
まず、内容が把握しやすくてメンテナンスがしやすい2番目を取ってみて、
本当に遅くなったと感じた(おそらくないと思うのだが)時、1番目を取るという方式がいいだろう。
7)クラスをnewしてオブジェクトを生成するより、オブジェクトリテラルを使う。
6)でより安全なクラス宣言の仕方を言っているが、実はこの記事全体は2年前に書いた内容で、今では好ましくないと思われる。
なぜなら、Javascriptではクラス宣言にも関数宣言にもfunctionキーワードを使うため、
クラスとして宣言しているのに間違って関数として実行してしまうおそれがあるからだ。
例えば、以下のように点を意味するPointクラスを定義したとしよう。
function Point(x,y) {
this.getX = function() {
return x;
}
this.getY = function() {
return y;
}
};
これは普通に以下のようにnewキーワードをつけて呼び出すと、問題なくオブジェクトを生成できるが、
var p = new Point(10, 15);
p.getX();
10
以下のようにnewをつけないと、グローバルオブジェクトを汚してしまう。
Point(10,15);
window.getX();
10
簡単な例だが、大規模なプロジェクトでは、探しにくいバグの元になるだろう。
なので、代わりにオブジェクトリテラルを使う方がいい。
例えば、上記のPointは以下のようにオブジェクトリテラルを使える。
function createPoint(x, y) {
return {
getX : function() {
return x;
},
getY : function() {
return y;
}
};
}
var p = createPoint(10, 15);
p.getX();
10
newをつける必要もなく、グローバルオブジェクトを汚すこともない。
Object.createを使うと、継承もできる。
なので、prototype方式を使ったクラス宣言も使う必要がなさそう。
Javascriptでオブジェクト生成はオブジェクトリテラルに限ると思う。
Oracle 12CのPluggable Database
DBにも仮想化が到来した。
Oracle 12CのPluggable Database機能を利用すると、
一つの物理マシンだけで、複数の仮想DBをコンテナDBというものに
まとめて管理できるそうだ。
詳しくは以下の記事を参照
http://www.publickey1.jp/blog/12/oracle_database_12c.html
仮想化は
Oracleのような大型アプリケーションから小さなクラスまで
応用できるものが多く、よくできた概念だと思う。
BeanShell その2
今回はBeanShellの使い方をメモっておく。
1)Beanshellのダウンロード先 :
http://www.beanshell.org/download.html
ここでbsh-X.XXX.jarをダウンロードする。
2)実行
BeanshellにはコンソールモードとGUIモードがある
テキストモードの実行方法:
java -jar bsh-X.XXX.jar
又は
java -cp bsh-X.XXX.jar; bsh.Interpreter
GUIモードは
java -cp bsh-X.XXX.jar; bsh.Console
3)基礎
文法はJavaと同じ。
違うのはInterpreterなので一行ずつ解析するということ。
また、クラス宣言ができないなどの一部制限もあるようだ。
BeanShellを実行すると以下のようなプロンプトが現れる。
bsh %
このプロンプト上でコードを一行ずつ実行させることができる。
以下は試しに打ってみたもの。
bsh % System.out.println("Hello");
Hello
bsh % import java.io.File;
bsh % File file = new File(".");
bsh % System.out.println(file.getCanonicalPath());
D:\down
bsh %
BeanShellでは変数宣言時に型宣言を省略することができる。
bsh % import java.math.BigDecimal;
bsh % money = new BigDecimal("500"); // 型宣言を省略。
bsh % System.out.println(money);
500
もちろん、LinuxのshファイルやWindowsのbat・cmdファイルのように
シェルスクリプトとしても活躍できる。
以下のソースをtest.bshに保存しておく。
import java.io.File;
File current = new File(".");
for (file : current.listFiles()) {
System.out.println(file);
}
それから、コマンドプロンプトから以下を入力して実行できる。
java -cp down\bsh-2.0b4.jar bsh.Interpreter test.bsh
又は、BeanShellのプロンプト上から
bsh % run("test.bsh");
という風にrunコマンドで実行できる。
runコマンドの代わりにsourceコマンドを利用すると、runコマンドと
結果は同じだが、スクリプト内の変数が続けて利用できる。
bsh % source("test.bsh")
...
結果....
...
bsh % System.out.println(current); // test.bshで宣言したcurrent変数が使える。
しかし、runコマンドではスクリプトファイル内で使った変数の利用はできない。
Java標準パッケージ以外に自作のJavaクラスも勿論利用できる。
4)Scripted Methods
BeanShellではメソッドを定義することができる。
int addTwoNumbers( int a, int b ) {
return a + b;
}
sum = addTwoNumbers( 5, 7 ); // 12
マニュアルに出てるサンプルだが、public / staticなどの修飾子を
わざとつけてみてもエラーにはならなかった。
しかし、何の効果もないだろう。クラス内にメソッドがあるわけでないので...
まるでJavascriptでグロバール関数を定義したのと同じ感じ。
BeanShellではメソッド定義時、型宣言を省略することができる。
add( a, b ) {
return a + b;
}
foo = add(1, 2); // 3
System.out.println(foo);
foo = add("Oh", " baby"); // "Oh baby"
System.out.println(foo);
まさにJavascriptのような感じ。
5)Scripted Object
BeanShellではJavaと同じ文法でクラスを定義することはできないが、
Scripted Objectというのを使って複数のメソッドと変数をまとめた
オブジェクトを返すことができる。
例)
person(pName, pAge) {
String name = pName;
int age = pAge;
toString() {
return "name : " + name + ", age : " + age;
}
isOlderThan(other) {
return age > other.age;
}
return this; // 最後にthisを返すのは必須だ。
}
bsh % java = person("java", 16)
bsh % print(duke.toString());
name : duke, age : 31
bsh % print(java.toString());
name : java, age : 16
bsh % print(duke.isOlderThan(java));
true
6)JavaからBeanShellを使う。
以下のサンプルソースで説明を省略する。
package dukelab.beanshell.test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import bsh.EvalError;
import bsh.Interpreter;
/**
* BeanShellとJavaとの連携をテストします。
*
* @author dUkE
*/
public class BeanShellTest {
public static void main(String[] args) throws EvalError, FileNotFoundException, IOException {
Interpreter ipr = new Interpreter();
// 単純に1行ずつ実行。
ipr.eval("int i = 2011;");
ipr.eval("print(i);");
// 結果 : 2011
// ReaderオブジェクトもOK.
StringReader sr = new StringReader(
"JOptionPane.showMessageDialog(null, \"こんなのもできるんだ。\");"
);
ipr.eval(sr);
// 結果 : ダイアログが表示される。
// スクリプトファイルの実行も勿論可能。
ipr.source("test.bsh");
// 結果 : ファイルのリストが出力される。
// Java側で変数をBeanShellのコンテキストに予め入れておくとスクリプト内で使用できる。
ipr.set("thisYear", 2011);
ipr.eval("print(\"this year : \" + thisYear);");
// 結果 : this year : 2011
// 実行した結果はJava側で使える。
File f = (File) ipr.eval("f = new File(\".\");");
System.out.println("path : " + f.getCanonicalPath());
// 結果 : path : 現在のディレクトリ。
}
}
7)自動importされるパッケージ
javax.swing.event
javax.swing
java.awt.event
java.awt
java.net
java.util
java.io
java.lang
8)BeahShellの主要コマンド
ディレクトリ関連
dir()
source()
run(),
cat()
load()
save()
mv()
rm()
addClassPath()
javap() - 指定したオブジェクトが持っているメンバーを見ることができる。
APIを調べたい時に便利だろう。
例)結果は皆同じ。
javap( Date.class );
javap( new Date() );
javap( "java.util.Date" );
javap( java.util.Date );
BeanShellの終了はexit()コマンドを使う。
importCommandsコマンドを使うと自分だけのコマンドが作れる。
9)BeanShellの活用
以下は私が個人的に注目する活用面だ。
実際、BeanShellだけでなく、Groovy、JRubyなど他のスクリプト言語でも
可能なことでもある。
だから「BeanShellの活用」ではなく「スクリプト言語の活用」
がより正しいタイトルだと思われるが、BeanShellのメモなので、
そのままおいておく。
1)プログラムの機能の一部をスクリプトで実装する。
=> コンパイルが要らないし、結果をその場で確認できるので、アジャイルな開発に役立ちそうだ。
アジャイルな開発? 簡単に言って"効率よく、早く開発する"を意味する。
コアな部分は、かなり重要なので以前のようにJavaで作るのが正しい。
それ以外の機能的な部分はスクリプトで作成したりすると、開発スピードがあがるような気がする。
機能の一部にスクリプトを使うプログラムは数多くある。
例えば、
AutoCadではLisp言語を
World of WarcraftではLua言語を
そんな理由で私はCompile + Interpreterのハイブリッド形式を最近、注目しつつある。
2)設定ファイルに動的にな設定ロジックを組み込める。
=> 例えば、年齢制限を男性 : 30歳未満、女性 : 25歳未満とする。
これは既存の方式ではどうしてもロジックの方(つまりJavaクラス)に入れなければならない。
性別が男子か女性かを判別するロジックを設定ファイルに書くことができなかったからだ。
しかし、スクリプトを使えば、例えば、
age = (sex == "男性" && age < 30 || (sex == "女性" && age < 25)
のように書くことができる。適当な例だが、私のためのメモなのでこれで十分だと思う(笑)。
10)総評
JavascriptとJavaを連携するのと変わりないような気もしたが、
Javaをそのままスクリプトで活用できるということは非常に魅力的だ。
Java文法だけ知っていれば、Javaの全ての資産をスクリプトで利用できるからだ。
JSR-274 the BeanShell Scripting Languageという標準もあるので
ただのJavaライブラリではない、標準のものなので、習っておくのも
悪くはないと思う。
しかも実行に必要なjarファイルは機能の割りにスーリムそのままだ。
(フール版が276KB、コア版が141KB)
さあ、使ってみようじゃないか。
11)参考URL
http://allabout.co.jp/gm/gc/80686/2/
http://journal.mycom.co.jp/column/jsr/031/index.html
BeanShell その1
BeanShellはJavaと似てる文法(70%ぐらいかな)を持つスクリプト言語だ。
つまり、プログラムソースをコンパイルせずにすぐ実行できるということだ。
BeanShellはJavaで作られていて、JVM上で動く。
今までJVM上で動く言語いくつかを見てきた。
例えば、JRuby、Jython、Scala、Groovy、Closureなど。。
これらの言語はJava文法の冗長さを減らし、言語の文法を表現豊かにし、
プログラムの作成を容易にしている。
それに並行処理機能など、言語特有の機能を付加したのもある。
真面目に勉強したScala言語を(今は思い出さないが -_-)振り返ってみると、
本当にJavaより少ない行数で多くのことができた。
しかし、問題は新しい文法を学ばなければならないということだ。
このコストは、われらのような会社員には決して軽いものではない。
われらには、飲酒、ゲーム、カラオケ、といった健全な文化を営む時間も
必要なのではないか。
Java言語文法をほぼそのまま活用できるBeanShellはこういう点で
格別なものだと思う。
もちろん、上記に並べた言語はスクリプトはもちろん、コンパイルもできるし、
メジャー級の機能を持っている。
それに比べるとBeanShellは小さいスクリプト言語に過ぎないので、
完全比較は無理だ。
しかし、JavaリソースをJavaと似てる文法でスクリプト的に活用するという
側面から見ると、断然BeanShellが有利ではないかと思う。
なぜなら、文法がJavaと似ていて、すごく簡単だからだ。
関数宣言とか、いくつか違う文法はあるが、そんなに難しくない。
BeanShellのBeanはJavaを特徴づけているだろう。
後ろのShellはスクリプトを強調しているだろう。
まさにJavaによるスクリプト。
ちなみにスクリプトファイル形態で実行できるだけでなく、
1:1のコンソールモードも持っている。
例えば、
import java.io.FileReader;
f = new FileReader("test.txt");
のようなソースを1行1行ずつ実行できる。
このBeanShellはJava標準の一つにもなった。
「JSR 274: The BeanShell Scripting Language」
という題名で...
次期JDKに標準で組み込まれるとすごく便利になりそうだ。
(ただし、組み込まれるかどうかは不明)
環境に必要なスクリプトをJavaで書いて実行する...
もうLinuxのbashかperlで難しいスクリプトを書かなくてもいいってこと。
環境スクリプトだけでなく、自分のプログラムに組み込んで活用することもできるし、
他のいくつかのプログラムでは既に使っている。
たとえば、JMeterでテストスクリプトの作成にBeanShellが使える。
スクリプト言語でプログラムの一部を構成するのはゲーム分野では
よくあることだ。特にLuaという言語が有名。これはWorld of Warcraftの
拡張モジュールを書くのに使われている。
次回はBeanShellの簡単な使用法と文法をまとめてみようか。
参考
http://journal.mycom.co.jp/column/jsr/031/index.html
Erlang 基礎ポイント1 - 紹介, 文法
1・2年ごとに新しい言語を勉強している。
Python・Scala・Lispに続けて、今年からはErlang.
メインはJava・Javascriptだが、他の言語を接することで
問題解決やアイデア作りに役立っているを実感している。
これから数回に分けて勉強した内容を書くつもり。
目標は網羅でなく、ポイントをつかむことだ。
Erlangとは
Erlangはエリクソン社が開発したプログラミング言語である。
少ないコード量で並列処理・ネットワーク処理を記述できる。
Linux・Windowsをはじめとして、色々なOSで動く。
参考書
練習問題が曖昧な部分があるが、大体読みやすい。
実行環境
- REPL(Read Eval Print Loop)ができるシェル(erl)を備えている。勉強や検証時にうってつけだ。
- プログラムがある程度規模がある場合、コンパイル(erlc)して実行(erl)する。
文法
行の最後にはピリオドを置く。
1> Fruit = "apple".
変数は大文字で始まる。
1> Fruit = "apple".
"apple"
小文字で始まると、アトムになる。
アトムはJavaのenum定数のようなものだと考えればいいだろう。
変数のようにメモリ番地を指すのではなく、
名前(リテラル)そのものが意味を持つ。
つまり、以下のappleはappleそのもので、メモリのある番地を
表すものではないのだ。
2> apple.
=を使った変数への代入は一回しかできない。
2回代入するとエラーになる。
10> Fruit = "apple".
"apple"
11> Fruit = "mango".
** exception error: no match of right hand side value "mango"
変数を不変にすることで、変数の値がどう変わるかをしなくていいので、
プログラムの把握がしやすい。
タプルは複数の要素を一つにまとめるもの。
Javascriptのオブジェクトリテラルに似ている。
2> Person = { name, "Duke" }.
{name,"Duke"}
実はErlangで=は代入でなくパターン照合を意味する。
6> Location = { "Japan", "Tokyo" }.
{"Japan","Tokyo"}
7> { Country, City } = Location.
{"Japan","Tokyo"}
8> Country.
"Japan"
9> City.
"Tokyo"
10> {A, atom} = { "Foo", atom}.
{"Foo",atom}
11> A.
"Foo"
Locationには、まだ値がバインドされていないので、Locationにタプルが入り、無事実行される
Locationに値が入っていたとしても、その値が{"Japan", "Tokyo"}なら、6行は真となる。
もし違う値が入っていたら、エラーとなる。
10行で左辺のatomは、ただのアトムであり、右辺のタプルと要素数を合わせるための
ダミーのようなものだ。
リストを作るためのネイティブ表記がある。
15> Planets = [{mercury, 1}, {venus, 2}, {earth, 3}].
[{mercury,1},{venus,2},{earth,3}]
16> [First,Second|Remaining] = Planets.
[{mercury,1},{venus,2},{earth,3}]
17> First.
{mercury,1}
18> Second.
{venus,2}
19> Remaining.
[{earth,3}]
22> lists:nth(1, Planets).
{mercury,1}
リストから要素を取り出したい時はパターン照合を使う。
listsモジュールのnthのような関数も使えるが、パターン照合の方が
Erlangらしくていいのでは?
今日はここまで。