基礎を終えた人のScalaミニtips
どう書く?orgでScalaを書いてくれる人もでてきたので、超一部の方向けにScalaのことでも書いてみようと思います。言うなれば、基礎を終えた人のScalaミニtips。知っている人は知っている、でもあまり知られていないことを並べていきます。
下に行くほどマニア度あがります、たぶん。FPよりの話が多いかもしれません。はやりのYコンビネータの話とか。たぶん。
ではいってみましょう。
Predefされているものは把握しておきましょう
Scalaにはscala.Predefというオブジェクトがあります。この中で定義されているものは常にインポートされていて使える状態になっているので把握しておきましょう。
例:
- def exit(status: Int): Nothing = {
- java.lang.System.exit(status)
- throw new Throwable()
- }
- def assert(assertion: Boolean) {
- if (!assertion)
- throw new java.lang.AssertionError("assertion failed")
- }
- def print(x: Any) = Console.print(x)
- def println() = Console.println()
- def println(x: Any) = Console.println(x)
C言語ライクなforはどうかくの?
こうです。
- val a = Array(1,2,3,4,5)
- var i= -1;while({i += 1; i <a.size;}) {
- println(a(i))
- }
setterを使おう
setHogeみたいなのは、カッコわるいです。RubyのアクセッサーしかりPythonのpropertyしかり、instance.name = value形式で扱えるのがモダンな言語というものです。
- class Test {
- var _name = "default"
- def name_=(newValue:String) { _name = newValue }
- def name = _name
- }
- val a = new Test
- a.name = "new"
- println(a.name)
単項演算子も定義できます。
できます。
- class Test {
- var _name = "default"
- def name_=(newValue:String) { _name = newValue }
- def name = _name
- def unary_- = "unary:" + name
- }
- val a = new Test
- a.name = "new"
- println(-a)
applyでオブジェクトをメソッドのように呼び出せるよね? hoge(index) = valueはオーバーライドできないの?
できますよ。なんとupdateというすげーふつーの名前のメソッドを定義するんです。
- object dictionary {
- val data = Array(null, "A","B","C")
- def apply(x:String) = x match {
- case "one" => data(1)
- case "two" => data(2)
- case "three" => data(3)
- }
- def update(x:String,y:String) = x match {
- case "one" => data(1) = y
- case "two" => data(2) = y
- case "three" => data(3) = y
- }
- }
- dictionary("one") = "X"
- dictionary("two") = "Y"
- dictionary("three") = "Z"
- println(dictionary("one")+","+dictionary("two")+","+dictionary("three"))
可変長引数は取れますか。また、リストや配列を展開してメソッドにわたせますか。
もちろん。
- def sumPlus(plus: Int, n: Int*) = plus + sum(n :_*)
JAVAのObject型可変長変数をとるメソッドはどう呼びますか?
ちょっとめんどくさいですが、こうです。
- String.format("%d %s", List(1, "hoge").map(_.asInstanceOf[AnyRef]).toArray)
インスタンスのメソッドを束縛できますか?そのとき、メソッドがオーバーロードされている場合はどうしますか?
こうします。オーバーロードされている場合は_の後ろに型をつけます。
- val format = (new SimpleDateFormat("dd")).format _:Date => String
ここからFPよりです。
カリー化はできますか?
Function.curriedを使います。uncurriedもあります。
- def test(i:int, j:int) = {
- printf("i:{0}, j:{1}", i, j)
- }
- val f = Function.curried(test _)(1)
- f(1)
遅延評価は?
lazyを使います。Streamも使いこなせるとハッピーです。
たとえば、無限フィボナッチ数列は以下のように定義します。
- lazy val fib: Stream[Int] = Stream.cons(0,
- Stream.cons(1, fib.zip(fib.tail).map(p => p._1 + p._2)))
先生、関数合成がしたいです・・・
Haskellでは短く直感的にかけるからいいですよね。
Scalaでは正直、逆に長ったらしくなりますが、どうしてもというなら・・・
- ({ x:int => x + 1 } andThen { x:int => x * 2 })(3) // => 8
- ({ x:int => x + 1 } compose { x:int => x * 2 })(3) // => 7
forはモナドに使える構文です。リスト内包表現用ではありません。
リストはモナドですし、HaskellのMaybeに相当するOptionというモナドもあります。map, flatMap, filterメソッドを実装すればforで書けるオブジェクトを定義できます。
Yコンビネータとかいうものの話が(一部で)盛り上がってますが、そういうのってScalaでできるんですか。型があるから複雑だと思うんだけど。
えーと、無名関数で再帰したいんでしょうか?こんな感じでどうでしょう?ふつーはこんなの使いませんけどね。
- def Y[A,B](f:((A=>B),A)=>B,x:A):B = f((x1:A)=>Y(f,x1),x)
- println(
- Y(
- (f:((int,int)) => int, arg:(int,int)) => arg match { case (x, y) => x match {
- case 0 => y
- case _ => f((x - 1, y + x))
- }} , (10, 0))
- )
さて、数少ない日本人Scala好きの皆さん。どれくらいご存知でしたでしょうか。まぁ、基礎からちょっとScalaやればこれくらいは皆さんご存知だと思うんですが、やはりScalaはカオスな言語なので、なかなか見つけられない機能も多いんで、最近Scalaやりはじめた人は参考にしてもらえるとうれしいです。
About this entry
You’re currently reading “基礎を終えた人のScalaミニtips,” an entry on inforno
- Published:
- 02.03.08 / 12am
- Tags:
- scala




No comments
Jump to comment form | trackback uri [?]