decadence

個人のメモ帳

Tips06 (Scala : itpro)

刺激を求める技術者に捧げるScala講座 - 刺激を求める技術者に捧げるScala講座---目次:ITpro
適当に読み終えたし必要な所だけ取り出した

なんか最初の方のコードが変なのは古いからだけじゃない気がする...

一応今の時点ではまだjavaにコレクションの操作が加わって便利って感じ > Scala
いやでもコレクション操作すごい便利…
後書く量がすごい減って良い感じ
後REPL便利

そういえばスクリプトのように書いたコードはスクリプト言語として実行されているわけじゃなくて,ちゃんとobjectに内包されて実行されているらしい.
正直特に何も意識してなかった…

2.8までデフォルト引数無かったんだ…
2.8からScala始めたゆとりだから…うん…
コレクションの変化とか見ると2.8から手出したのは良かったかもしれない...

きっと開発環境の後半はEmacs+ensimeが.

コレクション関係のtraitや@traitrecなどが良い感じ.

というわけで記事の抽出リストは以下

正規表現

val dt = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
val dt(year, month, day) = "2012-02-21"

オブジェクトを追加可能なコレクション

scala.collection.mutable.ArrayBuffer : 後尾に追加する場合に向いている
scala.collection.mutable.ListBuffer : 先頭に追加する場合に向いている

ちなみにArrayは長さは固定だけどmutableとか意味分からない感じになる
でも先頭以外の値の処理を多く行ないたい時などは効率が良い

Set : 重複を許さないコレクション(順序は無い)

値の数に応じEmptySet, Set1, Set2, Set3, Set4, HashSetが用いられている
Listからの変換

val data = List(1, 2, 3, 4, 5)
val set = Set.empty ++ data // Set(5, 1, 2, 3, 4)
val set = Set(data: _*) // よく分からんが上と同じ

括弧をつけてcontainsが行なえる -> applyメソッドがcontainsと等しい働きをする

set(3) // true
set(9) // false

追加と削除を行なう為にはimport scala.collection.mutable.Setを行い変更可能なSetを用意する必要がある

Map

Set同様,追加と削除を行なうにはmutableなMapを用意する必要がある

scala> val data = List((1, 10), (2, 20), (3, 30))
scala> val map = Map.empty ++ data
map: scala.collection.immutable.Map[Int,Int] = Map(1 -> 10, 2 -> 20, 3 -> 30)

Setと違い,applyはKeyとなってる値を指定する事でValueを取り出せる
値がなければNoSuchElementException
分からない場合の対処法はパターンマッチか,getOrElse(デフォルト値を設定出来る)を用いる
内容一覧はfor((key, value) <- map)として取り出せる
または,それぞれの組をTupleとして取り出して_1と_2で用いる事が出来る

for

まぁすごい

モナド

パターンのようなもの
モナドが成立してたら?モナドを満たしていたら?モナドを実装したら?
書き方分からん…
flatMapなどで色々と組み合わせたりする事が可能だから便利!
どこかにあったベルトコンベアの図が少し良かったかも…

でも何か少し違う所もある気がする
filterとかいらない?
参照透明性とは同じ式をいつ評価しても同じ値が返る性質の事

後で「モナドは象だ(Monads are Elephants)」日本語訳 — Japanese Translation of Monads are Elephants v1.0 documentation読むから流した...

ローカル関数

初期値入れて再帰したい時とか便利だよね
しかもいきなり引数のパターンマッチから始めたりしたらなんか良い感じだよね

構造化プログラミング,出来る限り意識してコード書いてます.大好き.

末尾再帰

アノテーション@tailrecについて
末尾再帰である事,その関数が継承でオーバーライドされない時に付ける.
コンパイル時に末尾再帰最適化が出来なかった場合,コンパイルエラーになる

こんな物があったのか…
関数型言語ほぼ初心者だしこれつけて末尾再帰ちゃんと書けてるかチェック出来るのか
ありがたい.

import scala.annotation._ する必要がある

コンパイルオプション

scalacのオプション -Xprint:erasure を付けると内部で処理されるコードの型情報が見れる

アノテーション@specializedについて.
def loop[@specialized("Int") T](a:Array[T],g:Func[T]):Long = {…
オプションに -Yspecializeをつけてコンパイルを行なうと,T=intの場合専用のコードを生成する.
この結果,boxing/unboxingの省略されたコードが生成される.
特定のboxingが多く発生する場合に使用すると良い

@specializedだけ格と,8個のプリミティブ型とUnit型に特化した9個のコードが生成される.
よってパフォーマンスに影響のある型パラメータをよく考えて選択する事が重要となる.

コレクションについて

trait scala.collection.TraversableLikeとは,要素を順に辿る事が出来るコレクションのトレイと.
この中で抽象メソッドforeachを用いてmap, flatMap, filterなどを実装している.
Listで使用されるforeachはTraversableLikeでの実装をLinearSeqLikeでオーバーライドしたもの
コレクションライブラリのパッケージ構造としては以下のようになる
scala.collection
  mutable/immutableに共通のコレクション用トレイトなど
  mixin用にメソッド実装を含んでいるtraitはXxxLikeの様な名前
scala.collection.mutable
  mutableなコレクションのクラス/トレイト群
  不変コレクションの組み立てに使用されるBuffer系のクラスも含む
scala.collection.immutable
  immutableなコレクションのクラス/トレイト群
scala.collection.generic
  コレクションの組み立てに使用するBuilderの取得に関わるクラス/トレイト群
  コレクションクラスの設計をする場合だけ使用する

Listクラスのメソッド定義で使用されるscala.collection下のコレクショントレイトは以下
・TraversableLike : abstract method newBuilder, foreachが宣言されたコレクション
  要素を連結するBuilderを返す,全要素を辿るforeachの定義が必須
・IterableLike : abstract method iteratorが宣言されたTraversableLike
  iteratorによりforeachを再定義可能
・SeqLike : abstract method length, apply(idx: Int)が宣言されたIterableLike
  lengthとapplyによりランダムアクセスが可能
・LinearSeqLike : abstract method isEmpty, head, tailが宣言されたSeqLike
  各々を用いて必要に応じforeachなどを再定義する事で効率的なコードに出来る

等価性

scala> List(1, 2) == Array(1, 2)
res29: Boolean = false
scala> List(1, 2) sameElements Array(1, 2)
res30: Boolean = true

javaとの互換性
> import scala.collection.JavaConversions._

パーザコンビネータ

何か少し専門寄りに…?
でも著者が好きだから流して読む

パーザコンビネータとは,構文解析を簡単に行なうためのライブラリの一種
文法定義ファイルを汎用のプログラミング言語で書くためのライブラリ.

パーサジェネレータ(yacc, JavaCC, etc)でなくパーザコンビネータを使う理由

  • > 拡張性,エラーチェックが容易

一応読んだ.
前にtiny Cのコンパイラyaccで,簡易OCamlのパーサーをOCamlで書いたし大体で良かった.

並行プログラミング

import scala.actors.Actor
class Hoge() extends Actor{ // Actorと例とを継承
	def act(){} // 必須
}
new Printer().start // startメソッドでアクターが動作を始める

Actorトレイトの主なメソッド(doc見れば良いんだけど…)
・act() : Unit
  アクターの動作を記述するメソッド。必須。
・! (msg: Any) : Unit
  指定された通信先へ指定された値を非同期に送信するメソッド。
・!? (msg: Any) : Any
  指定された通信先へ指定された値を送信し応答が返ってくるまで処理をブロックするメソッド。
・!! [A] (msg: Any, handler: PartialFunction[Any, A]) : Future[A]
  指定された通信先へ指定された値を非同期的に送信するメソッド。すぐにFuture(後述)が返ってくる。
・receive [R] (f: PartialFunction[Any, R]) : R
  自身に送られたメッセージを引数で与えられた関数で処理するメソッド。自身にメッセージがない場合は処理をブロックし、メッセージが到着したら再開する。
・receiveWithin [R] (msec: Long) (f: PartialFunction[Any, R]) : R
  receiveと同じだが、msecで指定した時間を超えてメッセージが到着しない場合、TIMEOUTオブジェクトが指定された関数に渡される。
・react (handler: PartialFunction[Any, Unit]) : Nothing
  receiveと同じように、自身に送られたメッセージを引数で与えられた関数で処理するメソッド。receiveより軽量。(次回詳しく解説します。)
・reactWithin (msec: Long) (handler: PartialFunction[Any, Unit]) : Nothing
  receiveWithin[と同じ。react版。

Liftについて

パス