Scala覚え書き その0 Windowsへのインストールと開発環境構築
Scalaを試した過程を淡々と記録していきます。
まず環境の構築。最近はMeadow上でruby-modeとかhaskell-modeとかを使って、インタプリタを呼びだしつついじるのが好きなので、Windowsへのインストール方法とscala-modeを探す。両方あっさりみつかった。
- ダウンロードサイト
- http://www.scala-lang.org/downloads/index.html
- scala-modeを使ってみた人の記録
- http://d.hatena.ne.jp/riue/20080105/1199552108
ダウンロードサイトより、IzPack Java Installerを落としてインストール。scala-mode.elは同梱されていたので、適当な場所にコピって.emacsにこんなふうに設定を書いて環境構築終了。
(setq load-path (cons "~/lib/elisp/scala" load-path)) (require 'scala-mode-auto) (setq scala-interpreter "C:/bin/scala/bin/scala.bat"))
Scala覚え書き その1 HelloWorldと関数定義と無名関数
HelloWorld
JRubyな高井さんのサイトに本家のチュートリアルの写経シリーズ(http://recompile.net/2007/07/a-scala-tutorial-for-java-prog.html)があったので、HelloWorldを試す。emacs上にコピペして、run-scalaしてC-cC-l。無事にHelloWorldが出力された。
//class HelloWorld { // クラス宣言 object HelloWorld { def main(args : Array[String]) { println("Hello, World") } } HelloWorld.main(null) // インタプリタで動かすためのコード
*1
このHelloWorldは"object宣言"で作られている。object宣言を使うとHelloWorldクラスを定義した上に、そのクラスのシングルトンオブジェクトを生成して、"HelloWorld"という名前と結びつけるらしい。HelloWorldはすでにオブジェクトなのでnewできない。class宣言というのもあって、それを使うとnewできるらしい。
元々のチュートリアルのコードには最終行は存在していない。コンパイルしてJavaのclassファイルを作った後にHelloWorldクラスを呼びだすとmain関数が呼ばれるらしい。最終行は、インタプリタに読みこませた時に出力されるように追加したもの。
じゃあクラス宣言にしたらこれでは動かないのかな、と思いきや、object宣言をclass宣言に置き変えても、HelloWorld.main(null)で無事に動いてしまった。class宣言だと、「HelloWorld」というのはインスタンスじゃなくてクラスになると思うんだけど、クラスからでもmainはそのまま呼べるのかな。インスタンスメソッドも呼べる仕様なのか、mainはインスタンスメソッドではないのか、それともクラスとインスタンスの境目があいまいなんだろうか。まだ謎。
関数定義
クラス定義やオブジェクト定義(?)をしなくても、べたにdefで関数定義ができるらし。というわけでお約束の階乗。
def fact(n:Int):Int = { if (n == 1) {1} else {(n * fact(n-1))} }
"(n:Int):Int"なあたりは引数と関数(の返り値)の型を宣言している。Scalaはある程度型推論をやってくれて、返り値の型は省略しても推論してくれる。引数の型は省略するとエラーになってしまった。残念。上の例で返り値の型まで書いてあるのは、再帰関数だと返り値の型も書かなきゃいけないようだから。これまた残念。
あとちょっと変わってるのが関数定義の構文。中括弧を多用するところはCに似てるので、Cのように関数シグネチャの後に直接{}って書いてたらパースエラーになった。"= {}"にしないといけないようだ。このへんの感覚は、無名関数をつくってから変数と結びつける雰囲気で関数型ぽい。
{}の中はどう書くか、というとこれはschemeやruby風。複数の式を羅列することができて、順番に実行される。最後の式の値が全体の値として返る。最後の式以外は副作用のある式を書くことになるんだろうな。きっと。
無名関数
じゃあ無名関数は、というと、これは"=>"で作れる。無名関数を作ってから変数に代入してみたりした。
def add(a:Int,b:Int) = {a+b} val add2= {(a:Int,b:Int) => a + b} val add3:Int=>Int=>Int = {a => b => a + b}
add3はカリー化されてるかんじか?変数の型は無名関数の入力に書いても、変数側にまとめて書いてもよい。けっこう柔軟。
ついでに変数の話も。valっていうのは変数の宣言なんだけど、もう一つvarってのもある。valは更新不能でvarは更新可能らしい。
val id = {n:Int=>n} var id2 = {n:Int=>n} // id = {n:Int=>n} //これはエラー id2 = {n:Int=>n+1}
valを使ったidへの再代入である3行目はエラーになっちゃうけど、varを使ったid2のほうは関数も更新できた。型はあってないと型エラーといわれてしまうけど、型さえあってりゃ関数の中身を書きかえられる。関数の中身を書き換えられるのに型のチェックはする、とも言えるか。どちらにしてもちょっと面白い。
まとめ
疲れてきたのでこのへんで適当にまとめ。
- 型指定はPASCAL風というかOcaml風というか基本は変数の後に型を書く。関数の返り値の型は関数シグネチャの直後に書く。
- 個人的には関数定義とは独立に型を指定できるhaskell風なのが好みなので残念。
- 関数の仮引数の型は必ず明示する必要がある
- 返り値の型は省略しても推論してくれる
- でも再帰になってると推論してくれない
- 関数定義に"="を忘れるな
- 無名関数は "=>"で定義可能
- 変数にはvalとvarの二種類ある。
基本は関数型ながら、手続型っぽい機能もシンプルに取りこんでる感じでわりと好感触。手続スキーな人から見ると真逆の感想になるかもしんない。
自分をデザイン
元ネタの本は読んでないけど、 自分は決めるものか探すものかって訊かれたら、私は圧倒的に「探すもの」派だなあ。
ただ、「探す」という言葉はちょっと誤解されやすい。「本当の自分」という完成品が どっかに転がってて、それを見つければゴール、みたいな感じにとられるおそれがあるから。
ここでの「探す」は、 木の塊を彫ったり粘土をこねたりして像をつくるとか、そういう感じ。 それは探すじゃなくてつくるじゃないか、と思うかもしれないが、 「もっともふさわしい表現を探す」とか「いちばんしっくりくるデザインを探す」 とかそういう時の「探す」って、「つくる」のとほとんど同義じゃないかな。
(2008/02/16 03:13:23 PST 自分探しんぐ)
この発想はまさに「自分をデザインする」という話で、いかにもschemerらしいなあと思った。
ところで、shiroさんの日記を引用したりブックマークしたりするにはどうすればいいのだろう。パーマネントリンクがなさげで困りはてた。半年くらい立つとこのリンクじゃ辿れなくなるよなあ。