programming in Scala: 斜め読みメモ

ちょっとひっかかったところのメモ集。あとでちゃんと読むために。

Scalaスケーラブルプログラミング[コンセプト&コーディング] (Programming in Scala)

Scalaスケーラブルプログラミング[コンセプト&コーディング] (Programming in Scala)

4.3 シングルトンオブジェクト

クラスメソッドの置き場

7.3.5 for yeild構文

構文としては
for <節> yeild <本体>
となっている。

scala> val ar = Array("sfdsas", "fdsa")
ar: Array[java.lang.String] = Array(sfdsas, fdsa)

scala> "ar".length
res19: Int = 2
                                            ^
scala> for { str <- ar  if str.length > 1 } yield str
res22: Array[java.lang.String] = Array(sfdsas, fdsa)

scala> val ks = for { str <- ar  if str.length > 1 } yield str
ks: Array[java.lang.String] = Array(sfdsas, fdsa)

scala> val kks =  for { str <- ar  if str.length > 1 } yield str + "asf"
kks: Array[java.lang.String] = Array(sfdsasasf, fdsaasf)

scala> for { k <- kks} println(k)
sfdsasasf
fdsaasf

7.4.4 try式による例外処理:値の生成

scala> def f(): Int = try {return 1} finally { return 2 }
f: ()Int

scala> f()
res0: Int = 2

scala> def g(): Int = try {1 } finally {2}
g: ()Int

scala> g()
res1: Int = 1

というわけで、字面と結果がうまくマッチしないんで、finallyでは値を返すな、と。終了処理の副作用のみにトドメよとのお告げ。

8.7クロージャー

自由変数はvar(ミュータブル)でもかまわないらしい。変更が反映される。

scala> def sum (a: Int, b: Int, c: Int) = a + b + c + 2
sum: (Int,Int,Int)Int

scala> def s2sum = sum (s: Int, 2, 3)
s2sum: Int

scala> s2sum
res4: Int = 12

scala> s = 6
s: Int = 6

scala> s2sum
res6: Int = 13

ただし、変数が変化していく場合、定義されたときのものが使われる

scala> def makef (more: Int) = (x: Int) => x + more
makef: (Int)(Int) => Int

scala> var m = 1
m: Int = 1

scala> val m1 = makef(m)
m1: (Int) => Int = 

scala> m1(1)
res7: Int = 2

scala> m = 2
m: Int = 2

scala> m1(1)
res9: Int = 2

scala> val m2 = makef(m)
m2: (Int) => Int = 

scala> m2(1)
res10: Int = 3

scala> m = 3
m: Int = 3

scala> m2(1)
res12: Int = 3

scala> m1(1)
res13: Int = 2

8.8 連続パラメータ

要するに可変長引数のことだが、Arrayを直接渡すときには技が必要らしい

scala> def plll(args: String*) = for (arg <- args) println(arg)
plll: (String*)Unit                  ^

scala> plll("aa", "aa")
aa
aa

scala> val ar = Array("sfdsas", "fdsa")
ar: Array[java.lang.String] = Array(sfdsas, fdsa)

scala> plll(ar)
:7: error: type mismatch;
 found   : Array[java.lang.String]
 required: String
       plll(ar)
            ^

scala> plll(ar: _*)
sfdsas
fdsa

8.9 tail recursion

Java VMの制限のためか、Scalaでは今のところ単純なケースしかoptimizeされないそうだ。
相互再帰のケースはダメだとか。

9.1 p.162のしっくりこないところ

_のプレースホルダーが使えるのはわかる。で、queryという自由変数を掴んだクロージャーだとどこが上手いのかよくわからん。

9.3 Curry化

プレースホルダを使えば、途中の関数も拾い出せる。アンダースコアは、離して書いてもいい。

scala> def cursum (x: Int)(y: Int) = x + y
cursum: (Int)(Int)Int

scala> val c1 = cursum(1)_
c1: (Int) => Int = 

scala> c1(2)
res3: Int = 3

scala> def c1f(y:Int) = cursum(1)(y)
c1f: (Int)Int

scala> c1f(2)
res4: Int = 3

9.4 loan patternを書ける

普通のカッコと中カッコ{ }の使い分けについては、あんまりピンと来ないが、loan patternを素直に書けるという話は覚えておきたい。

def withBroker(resource: ResourceType)(op: ResourceCluncher => Unit) {
  val cluncher = new ResourceCluncher(resource)
  try {
    op(cluncher)
  } finally {
    cluncher.close
  }
}

val file = new File("date.txt")
withBroker(file) {
  cluncher => cluncher.println(new java.util.Date)
}

上記の場合、withBrokerの2番目の引数を{ }で括っているのが味噌だというのだが、、、うーん。

9.5 名前渡しパラメータ

うーん、これ黒魔術ですかw

var assersionsEnabled = true
def byNameAssert(predicate: => Boolean) =
  if (assertionsEnabled  && ! predicate )
    throw new AssertionError

def byNameAssert(predicate: () => Boolean) とすると、呼び出すときに byNameAssert(() => 3 < 5) という風になって() => が省略できないが、上記のようにすると省略できる、、、そうです(汗

12 trait

mix-inだということ

14 表明

assert()とensuring()が使える。事後の保証もできる。この章はテストツールの紹介になっている。

15ケースクラスとパターンマッチ

Erlangなどでいうところのガードの話とか、パターンマッチとか。結構複雑なので、当面は覚えないw 脳みその節約せねばw

21 暗黙の型変換

必要な部分だけ、既存のクラスを拡張したいときに、implicitを使う

24 抽出子(extractors)

パターンマッチした結果を使いたい場合。unapplyを持つオブジェクトを定義する。

30 アクターと並行プログラミング

やっと、30/33で並行処理が出てきた。この冷遇っぷりは何w
要するにJavaに並列処理のツールはあると、それに加えてアクターのモデルを提供してますよ、そこんとこだけ説明しますよ、というスタンスである。
アクター、すなわちデータの共有をせず、メッセージ交換で協調動作します。ということ

  • アクターはstart()で起動できる
  • '!'メソッドでメッセージを送る
  • 部分関数を引数としてreceiveを呼び出してメッセージを受け取る
  • 普通のJavaシステムでは数千個のスレッドしかもてないし、スレッド切り替えも重いので、スレッド切り替えを節約できるreactというメソッドもあるらしい
  • receiveするアクターは、実際の処理は別のアクターに投げちゃって、自分はブロックせずに次のメッセージを待つ、というお作法
  • イミュータブルなデータだけ取り扱えば、スレッドセーフは自明

31 parser combinator

パーサの書きかた。DSLご用達。あとでちゃんと読む。