Scala Cookbook
2017-05-23T08:48:54+00:00
http://xerial.org/scala-cookbook
Taro L. Saito
leo@xerial.org
Logging
2017-01-20T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2017/01/20/logging
<p>プログラムの挙動を確認するのにはlogger(ロガー)を使います。
Scalaで使えるロガーには<a href="https://github.com/typesafehub/scala-logging">scala logging</a>, <a href="https://github.com/twitter/util#logging">twitter-util logging</a> などがありますが、ここではもっとも手軽に使える<a href="https://github.com/wvlet/log">wvlet-log</a>について紹介します。</p>
<p><strong>build.sbt</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>libraryDependencies += "org.wvlet" %% "wvlet-log" % "1.1"
</code></pre>
</div>
<p><strong>MyApp.scala</strong></p>
<p><code class="highlighter-rouge">wvlet.log.LogSupport</code>をクラスに追加します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>import wvlet.log._
object MyApp with LogSupport {
// ログのフォーマットを指定します
Logger.setDefaultFormatter(LogFormatter.SourceCodeLogFormatter)
info("log with source code")
}
</code></pre>
</div>
<h3 id="出力">出力</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>[MyApp] log with source code - (MyApp.scala:7)
</code></pre>
</div>
<p>より詳しい使い方は<a href="https://github.com/wvlet/log">こちら</a>を参考にしてください。フォーマットを指定することで、好みに応じてカラフルで詳細なログメッセージを出力することができます。</p>
<p><img src="https://raw.githubusercontent.com/wvlet/log/master/docs/images/formatters.png" alt="wvlet-log" /></p>
<h2 id="各種loggerライブラリの違い">各種Loggerライブラリの違い</h2>
<p>Scalaでのロギングにはバックエンドで使う実装の違いにより特徴が異なります。</p>
<h3 id="slf4j">slf4j</h3>
<ul>
<li>プログラム中ではログレベルの設定を行わず、外部の設定ファイル(logback.xmlなど)を使います。</li>
<li>slf4j-nop.jar (何も出力しない), logback-classic.jar (<a href="http://logback.qos.ch/">logback</a>を使う)などのslf4j用バインディングをライブラリに含めることでロガーの出力先を切り替えることができます。</li>
<li><a href="https://github.com/typesafehub/scala-logging">scala logging</a>は、slf4jをScalaから使うためのインターフェースを提供しています。</li>
<li>インターフェースが単純なため、採用しているプロジェクトが多くあります。</li>
<li>利用者が多い反面、slf4jのバインディングをdependencyに含めているプロジェクトも多く(Hadoopなど)、出力先を適切に切り替えるため依存関係から不要なslf4jバインディングを取り除かなければならない傾向があります。</li>
</ul>
<h3 id="javautillogging">java.util.logging</h3>
<ul>
<li>Javaのコアライブラリに含まれているため、slf4jのようにバインディングの実装を必要とせず、どんなプロジェクトでも使えます</li>
<li>コード内でログレベルやフォーマットの設定ができるので自由度が高いです。<a href="https://github.com/prestodb/presto">Facebook Presto</a>など大規模なプロジェクトでも使用されています。Twitter社の各種Scalaプロジェクトでも、<a href="https://github.com/twitter/util#logging">twitter-util logging</a> を通して使われています。</li>
<li><a href="https://github.com/wvlet/log">wvlet-log</a>もjava.util.loggingをベースに実装されています。ソースコードの行数を表示できるのでコードの実行箇所を確認しやすくなるのが大きな利点です。また、Scalaマクロを用いたコード生成を行うことで不必要なログメッセージを出力しない最適化がなされており、ロギングによる性能の劣化を気にせず使用することができます。</li>
</ul>
Parallel/Sequentialコレクションへの変換
2013-02-26T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2013/02/26/converting-parallel-collections
<p>マルチコア(スレッド)で並列処理可能なparallelコレクションへの変換には<code class="highlighter-rouge">par</code>を使います。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> val s = for(i <- 0 until 10) yield i
s: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> val double = s.par.map(_*2) // 並列処理される
double: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)
</code></pre>
</div>
<p>一方、sortingなど2013年現在のScalaではsequentialコレクションにしか提供されてない操作もあります。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> double.sorted
<console>:10: error: value sorted is not a member of scala.collection.parallel.immutable.ParSeq[Int]
double.sorted
^
</code></pre>
</div>
<p>そのような場合は、<code class="highlighter-rouge">seq</code>メソッドを使ってsequentialコレクションに戻す必要があります。以下は逆順に並べ替える例。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> double.seq.sorted(Ordering[Int].reverse)
res2: scala.collection.immutable.Seq[Int] = Vector(18, 16, 14, 12, 10, 8, 6, 4, 2, 0)
</code></pre>
</div>
<h3 id="参考">参考</h3>
<ul>
<li><a href="http://docs.scala-lang.org/overviews/parallel-collections/conversions.html">Parallel collection conversions - Scala Documentation</a></li>
</ul>
Type Class
2013-02-05T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2013/02/05/type-class
<p><strong>Type Class</strong>(型クラス) とは型の性質を表現するためのクラスで、Haskellなどの関数型言語では古くから使われています。型クラスは、アルゴリズムとアルゴリズム中で使うデータ型の結合を緩やかにする、あるいは、アルゴリズム中で使うデータと実際のデータ型の型合わせをするために使われます。</p>
<h2 id="例題">例題</h2>
<p>例えば、区間データ(start, endのフィールドを持つ)を保持するための<code class="highlighter-rouge">IntervalHolder</code>を考えてみます。区間を保持するという意味では汎用的に書けそうなので、区間を<code class="highlighter-rouge">A</code>と置いてGenericなクラスとして<code class="highlighter-rouge">IntervalHolder</code>を表現してみます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class IntervalHolder[A] {
// 区間をstartをindexとして保持したい
private var holder = Map[Int, A]()
def +=(a:A) {
holder += a.start -> a // コンパイルエラー。Aはstartを持つ型ではない
}
}
</code></pre>
</div>
<p>Aにはstartというパラメータは定義されていないので、Aにinterfaceなどを加える必要があります。</p>
<h2 id="型クラスを使わない場合traitを使用">型クラスを使わない場合(traitを使用)</h2>
<p>IntervalHolderを任意のAではなく、区間を表すIntervalData traitを継承した型のみを受け付けるように変更します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>trait IntervalData {
def start: Int
def end: Int
}
class IntervalHolder[A <: IntervalData] {
private var holder = Map[Int, A]()
def +=(a:A) {
holder += a.start -> a // コンパイルできるようになった
}
}
</code></pre>
</div>
<p>しかし実際には、区間データの表現には以下のように様々な種類が考えられます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>case class Interval(start:Int, end:Int)
case class SelectedRange(name:String, left:Int, right:Int)
</code></pre>
</div>
<p>これらは必ずしもstartというパラメータを持つわけではないが、区間として「みなせる」ようなデータ構造です。IntervalHolderのコードを再利用したい場合、これらの区間データのクラスをすべてIntervalData traitを継承するように書き直す必要があります。しかし、第三者の作成したライブラリ中のクラスなど、自分で書き直すのが難しい場合にはこの方法は使えません。</p>
<h2 id="型クラスを使って型を合わせる">型クラスを使って型を合わせる</h2>
<p>ここで登場するのが型クラスです。型クラスは任意のオブジェクト<code class="highlighter-rouge">A</code>から必要なデータ(ここではstartとend)を取り出せるように表現します。区間の性質を表す型クラス IntervalTypeを定義します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>trait IntervalType[A] {
def start(a:A) : Int
def end(a:A) : Int
}
</code></pre>
</div>
<p>IntervallHolderを型クラスである<code class="highlighter-rouge">IntervalType</code>を使って書き直します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class IntervalHolder[A](implicit iv:IntervalType[A]) {
private var holder = Map[Int, A]()
def +=(e:A) {
holder += iv.start(e) -> a // 型クラス経由でパラメータにアクセスする
}
}
</code></pre>
</div>
<p>次に、implicit parameter <code class="highlighter-rouge">iv</code>をコンパイラに自動的に見つけさせるため、Interval, SelectedRangeのそれぞれについて、型クラスIntervalTypeの実装をIntervalHolderのコンパニオンオブジェクト内に作成します(コンパイラが見つけられるスコープ中にあれば他の場所に定義しても構いません)</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object IntervalHolder {
// Intervalは、IntervalTypeとして扱えるという意味
object StandardInterval extends IntervalType[Interval] {
def start(a:Interval) = a.start
def end(a:Interval) = a.end
}
// SelectedRangeもIntervalTypeとして扱えるという意味
object SelectedRangeAsInterval extends IntervalType[SelectedRange] {
def start(a:SelctedRange) = a.left
def end(a:SelectedRange) = a.right
}
}
</code></pre>
</div>
<p>型クラスのインスタンスは1つあれば十分なのでobjectとして定義してあります。またimplicit paramterとして自動解決する場合にもobjectとしてあると都合がよいです。</p>
<h3 id="使用例">使用例</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>val holder = new IntervalHolder[Interval]
holder += Interval(1, 3)
val rangeHolder = new IntervalHolder[SelectedRange]
rangeHolder += SeletedRange("user input", 140, 180)
</code></pre>
</div>
<p>IntervalHolderの実装を2種類のデータ型に対して再利用することができました。今後区間を表すデータ型の種類が増えたときも、型クラスの実装を追加するだけでIntervalHolderを使えるようになります。</p>
<p>implicit parameterに代入される型クラスは、コンパニオンオブジェクト内に定義されているか(IntervalHolder, Interval, SelectedRangeのコンパニオンオブジェクトなどが検索対象に入る)、import文などでスコープに読み込んであれば、Aの型に合わせて対応するIntervalTypeの実装をコンパイラが見つけてきてくれます。</p>
<h2 id="型クラスの応用例">型クラスの応用例</h2>
<p>Scalaに含まれている<a href="http://www.scala-lang.org/api/current/index.html#scala.math.Ordering">Ordering</a>なども型クラスの一例です。<code class="highlighter-rouge">def lt(x:T, y:T): Boolean</code>など汎用的なT型の大小を比較するための関数が定義されている型クラスで、これを使うことによりsorting, min, maxなどを求めるコードを種々のデータに対して再利用しています。</p>
Reflectionで型情報を取得
2013-02-01T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2013/02/01/reflection
<p>Scalaでは<a href="http://docs.scala-lang.org/overviews/reflection/overview.html">Reflection</a>を使うとgenericsの型情報など詳細な型情報を取得することができます。</p>
<h2 id="クラス情報を取得-scala210以前">クラス情報を取得 (Scala2.10以前)</h2>
<p>Scala2.10以前では、以下のように型情報を取得できます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>case class Person(id:Int, name:String, age:Option[Int])
val c = classOf[Person] // Class[Person]を取得
c.getSimpleName // Person
c.getName // Personクラスのパッケージ名を含むfull path
</code></pre>
</div>
<p>しかし、<code class="highlighter-rouge">Person</code>クラスにどのような型の変数が定義されているか知りたい場合、</p>
<ol>
<li>javaのReflection機能を使う。<code class="highlighter-rouge">Class.getDeclaredFields/Methods</code>など</li>
<li>javapや<a href="http://asm.ow2.org/">ASM</a>などでコンパイル後のバイトコードを直接参照</li>
<li>ScalaSigを使う</li>
</ol>
<p>などの方法がありますが、どれも直接的でなくコーディングが大変でした。また、1や2の方法では<code class="highlighter-rouge">age:Option[Int]</code>などgenericなクラスの型パラメータ(この場合は<code class="highlighter-rouge">Int</code>)までは取得できません。なぜなら、コンパイル後のバイトコードでは<code class="highlighter-rouge">Option[Int]</code>は<code class="highlighter-rouge">Option[java.lang.Object]</code>と型情報を削られた形で表現されてしまうからです(<strong>type erasure</strong>と呼ばれます)。そのためJava(少なくともJava1.7の時点)では<code class="highlighter-rouge">Option[Int]</code>の型を正確にプログラム中から調べることは不可能でした。</p>
<p>このtype erasureを克服するため、Scalaではsignatureと呼ばれる情報がコンパイル後のクラスファイルにこっそり埋め込まれています。これにアクセスするのが3の方法ですが、Scalaの型の取り扱いについての深い知識が要求され、すぐに使いこなすのは難しいでしょう。</p>
<h2 id="typetagを使う-scala210の新機能">TypeTagを使う (Scala2.10の新機能)</h2>
<p>Scala2.10ではTypeTagが導入されsignatureへのアクセスが比較的容易になりました。</p>
<h3 id="準備">準備</h3>
<p>reflectの機能はScalaの本体とは別になっているので、sbtの<code class="highlighter-rouge">libraryDependencies</code>に以下の設定を追加します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>"org.scala-lang" % "scala-reflect" % "2.10.0"
</code></pre>
</div>
<h3 id="型情報を取得するコード例">型情報を取得するコード例</h3>
<p><code class="highlighter-rouge">case class Person(id:Int, name:String, age:Option[Int])</code>を定義して、パラメータの型情報を取り出します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def getType[A : TypeTag](obj:A) : Type = typeOf[A]
</code></pre>
</div>
<p>のように書くと、コンパイラが<code class="highlighter-rouge">obj:A</code>の型情報(TypeTag)を生成し、<code class="highlighter-rouge">typeOf[A]</code>でコード中に型情報を取り出せるようになります。</p>
<h4 id="コード">コード</h4>
<div class="highlighter-rouge"><pre class="highlight"><code>// この2行でScala2.10のreflectionの機能が使えるようになる
import scala.reflect.runtime.{universe => ru}
import ru._
object ExtractTypeInfo extends Logger {
// 任意のオブジェクトからTypeTagを取得。取得できない場合はコンパイルエラーになる
def getType[A : TypeTag](obj:A) : Type = typeOf[A]
// TypeからClass[_]情報を取得するためのミラー
val mirror = ru.runtimeMirror(Thread.currentThread.getContextClassLoader)
// Type情報を再帰的に解決
def resolveType[T](tpe:T) : String = tpe match {
// TypeRefから型情報を抜き出す
case tr @ TypeRef(prefix, symbol, typeArgs) =>
// Typeに対応するClassを取得
val cl = mirror.runtimeClass(tr)
var className =
if(typeArgs.isEmpty)
cl.getSimpleName
else // 型パラメータを持っている場合、各パラメータの型を解決
s"${cl.getName}[${typeArgs.map(resolveType(_)).mkString(", ")}]"
// コンストラクタで定義されているパラメータを取得
val cc = tr.declaration(ru.nme.CONSTRUCTOR)
if(cc.isMethod) { // コンストラクタの有無をチェック
// コンストラクタの最初の括弧内のパラメータ情報を取り出す
val fstParen = cc.asMethod.paramss.headOption.getOrElse(Seq.empty)
val params = for(p <- fstParen) yield {
val name = p.name.decoded // パラメータ名を取得
val t = resolveType(p.typeSignature) // パラメータの型を取得し解決
s"$name:${t}"
}
if(!params.isEmpty)
className += s"(${params.mkString(", ")})"
}
className
}
case class Person(id:Int, name:String, age:Option[Int])
def main(args:Array[String]) {
val p = Person(1, "leo", None)
val tpe = getType(p)
val t = resolveType(tpe)
println(t)
}
}
</code></pre>
</div>
<h3 id="実行結果">実行結果</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>Person(id:int, name:String, age:scala.Option[int])
</code></pre>
</div>
<p>上記のコードでは、<code class="highlighter-rouge">Option[T]</code>の型パラメータまで調べることができ、ScalaのInt型などは実際にはJavaのprimitive型のintになっていることがわかります。</p>
<h2 id="型の比較">型の比較</h2>
<p><code class="highlighter-rouge">typeOf[A]</code>で取得した<code class="highlighter-rouge">Type</code>は、<code class="highlighter-rouge">=:=</code>を使って以下のように比較できます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val tpe = typeOf[Int]
tpe match {
case t if t =:= typeOf[Short] => "is short type"
case t if t =:= typeOf[Boolean] => "is boolean type"
case t if t =:= typeOf[Byte] => ...
case t if t =:= typeOf[Char] =>
case t if t =:= typeOf[Int] =>
case t if t =:= typeOf[Float] =>
case t if t =:= typeOf[Long] =>
case t if t =:= typeOf[Double] =>
case t if t =:= typeOf[String] =>
}
</code></pre>
</div>
<h2 id="classaからsignatureを取得">Class[A]からsignatureを取得</h2>
<p>コンパイル時にTypeTagが得られない場合(例えばクラス名だけからオブジェクトを動的に作成する場合など)、Class[A]の情報からmirrorを経由してsignatureを取り出すこともできます。</p>
<h3 id="コード例">コード例</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>val cl = classOf[Person]
val mirror = ru.runtimeMirror(Thread.currentThread.getContextClassLoader)
// クラス名からClassSymbol (Type)情報を取り出す
val classSymbol : ru.ClassSymbol = mirror.staticClass(cl.getCanonicalName)
// コンストラクタを調べる
val cc = classSymbol.typeSignature.declaration(ru.nme.CONSTRUCTOR)
val params = if(cc.isMethod) {
val fstParen = cc.asMethod.paramss.headOption.getOrElse(Seq.empty)
for(p <- fstParen) yield {
val name = p.name.decoded
val tpe = resolveType(p.typeSignature) // 上記のコードを呼び出す
s"$name:$tpe"
}
}
else Seq.empty
println(params.mkString(", ")) // id:int, name:String, age:scala.Option[int]
</code></pre>
</div>
<h2 id="xerial-lens型情報を取得するライブラリ">xerial-lens:型情報を取得するライブラリ</h2>
<p>Scala2.10のreflectionの機能は強力ですが、上記のように再帰的な処理が必要となるなどやや不便なところがあります。これを解決するために<code class="highlighter-rouge">xerial-lens</code>というライブラリを作成しました。</p>
<p>sbtの<code class="highlighter-rouge">libraryDependencies</code>に、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>"org.xerial" % "xerial-lens" % "3.1"
</code></pre>
</div>
<p>を追加すると、型情報を取り出す<a href="https://github.com/xerial/xerial/blob/develop/xerial-lens/src/main/scala/xerial/lens/ObjectType.scala">ObjectType</a>が使えるようになります。</p>
<p>内部ではTypeTagだけではなくScalaSigにアクセスして詳細な型情報を取り出すなどの工夫がされています。</p>
<h3 id="使用例">使用例</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>import xerial.lens.{ObjectType,StandardType,Primitive, MapType}
val ot = ObjectType(classOf[Person])
println(ot) // Person
// パターンマッチで型による場合分けが可能
val params = ot match {
case s @ StandardType(cl) => s.constructorParams.mkString(", ")
case Primitive.Int => "int type"
case m @ MapType(cl, keyType, valueType) => s"Map[$keyType, $valueType]"
case _ => "no params"
}
println(params) // id:Int, name:String, age:Option[Int]
</code></pre>
</div>
<p>xerial-lensには、その他にもメソッドやアノテーションの情報を取り出す<a href="https://oss.sonatype.org/service/local/repositories/releases/archive/org/xerial/xerial-lens/3.1/xerial-lens-3.1-javadoc.jar/!/index.html#xerial.lens.ObjectSchema">ObjectSchema</a>や、それを利用してコマンドラインプログラムの作成を簡単にする<a href="https://oss.sonatype.org/service/local/repositories/releases/archive/org/xerial/xerial-lens/3.1/xerial-lens-3.1-javadoc.jar/!/index.html#xerial.lens.cui.Launcher">Launcher</a>などが含まれています。</p>
<ul>
<li>ソースコードはこちら <a href="https://github.com/xerial/xerial">xerial at github</a></li>
</ul>
<h2 id="関連">関連</h2>
<ul>
<li><a href="http://docs.scala-lang.org/overviews/reflection/overview.html">Scala本家によるReflection機能の紹介</a></li>
</ul>
文字列に式を埋め込んで整形する
2013-01-30T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2013/01/30/string-interpolation
<p>Scala2.10より、<a href="http://docs.scala-lang.org/overviews/core/string-interpolation.html">String Interpolation</a>の機能が追加され、文字列中に式を埋め込むのが容易になりました。</p>
<h2 id="使い方">使い方</h2>
<h3 id="s-string">s String</h3>
<p>double quotationの前に<code class="highlighter-rouge">s</code>を付けると、文字列中にある<code class="highlighter-rouge">$(変数名)</code>が置き換わる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val w = "World"
val message = s"Hello $w!"
println(message) // Hello World! と表示される
</code></pre>
</div>
<p><code class="highlighter-rouge"><span class="p">{}</span></code>で囲むと、任意の式を含めることもできる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>println(s"2 * 3 = ${2 * 3}") // 2 * 3 = 6 と表示される
</code></pre>
</div>
<h3 id="f-string">f String</h3>
<p>文字列に<code class="highlighter-rouge">f</code>をつけると<a href="http://docs.oracle.com/javase/1.6.0/docs/api/java/util/Formatter.html#detail">printf</a>の構文が使えるようになる。<code class="highlighter-rouge">$(変数名)%(フォーマット指定)</code>を文字列に埋め込むと変数の内容を表示するときのフォーマットが指定できる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val dollarToYenRate = 80.0
val budget_d = 10000000
println(f"Currency conversion: $budget_d%d to ${budget_d * dollarToYenRate}%,.2f yen")
</code></pre>
</div>
<p>f Stringでは、フォーマット指定を省くと文字列(<code class="highlighter-rouge">%s</code>と同じ)と扱われる。</p>
<p>フォーマット指定と実際の変数の型が異なると、コンパイル時にエラーがでる(type safeになる)ので、printf実行中のエラーを防げるようになった。</p>
<h2 id="formatによく使うシンボル">formatによく使うシンボル</h2>
<table>
<thead>
<tr>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="highlighter-rouge">%s</code></td>
<td>文字列</td>
</tr>
<tr>
<td><code class="highlighter-rouge">%d</code></td>
<td>整数</td>
</tr>
<tr>
<td><code class="highlighter-rouge">%f</code></td>
<td>浮動小数点数</td>
</tr>
<tr>
<td><code class="highlighter-rouge">%e</code></td>
<td>科学計算用の指数を含んだ数字。e-10などが付く</td>
</tr>
</tbody>
</table>
<h3 id="flagの例">flagの例</h3>
<p><code class="highlighter-rouge">%</code>と上記のシンボルの間にflagを複数個挟むことができる。</p>
<table>
<thead>
<tr>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="highlighter-rouge">,</code></td>
<td>3桁ごとにcommaを挟んで表示</td>
</tr>
<tr>
<td><code class="highlighter-rouge">(数字)</code></td>
<td>数字で指定された分のスペースを使って表示。<code class="highlighter-rouge">-</code>を付けると右寄せ</td>
</tr>
<tr>
<td><code class="highlighter-rouge">.2</code></td>
<td>小数点以下二桁を表示</td>
</tr>
</tbody>
</table>
15分で始めるScala
2012-11-29T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/11/29/scala-in-15-minutes
<p>これはScalaを使った開発環境を素早く整え、実際の開発の雰囲気を感じてもらうための文章です。</p>
<h2 id="update">Update</h2>
<ul>
<li>2013-07-23: Scala 2.10.2に対応しました</li>
</ul>
<h2 id="ここでできるようになること">ここでできるようになること</h2>
<ul>
<li>Scalaプロジェクトの作成</li>
<li>簡単なScalaコードの作成</li>
<li>テストコードの実行
<ul>
<li>開発しながらテストを行なう</li>
<li>ログの表示</li>
<li>コードの実行時間の計測</li>
</ul>
</li>
<li>システムにインストールできる形のパッケージを作成</li>
</ul>
<h2 id="準備">準備</h2>
<ul>
<li>UNIX環境(Linux、 Mac OS X、あるいは <a href="http://cygwin.com">Cygwin</a> をWindowsでセットアップする)</li>
<li>javaコマンドが使えること (環境変数PATHの設定など)</li>
<li>その他、curl, GNU makeなどのコマンド</li>
<li>インターネット接続</li>
</ul>
<p>(ここから15分です)</p>
<h2 id="scalaプロジェクトの作成">Scalaプロジェクトの作成</h2>
<p>Scalaプロジェクトの必要最低限のひな形をGitHub上に<a href="https://github.com/xerial/scala-min">scala-min</a>として作成してあります。以下のようにダウンロードしながら展開します。</p>
$ mkdir myproject
<div class="highlighter-rouge"><pre class="highlight"><code>$ cd myproject
$ curl -L https://github.com/xerial/scala-min/archive/master.tar.gz | tar xvz --strip-components=1
</code></pre>
</div>
<p><strong>備考</strong>: <a href="http://github.com">GitHub</a>はオープンソースでのコード開発を支援するサービスです。Scala自身の開発もここで行われています。</p>
<h2 id="テストコードの実行">テストコードの実行</h2>
<p>Scalaのプログラムは、<a href="http://www.scala-sbt.org">sbt(Simple Build Tool)</a>を使って開発するのが標準になっています。上でダウンロードしたプロジェクト内で、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt test
</code></pre>
</div>
<p>とすると、まずScala関連のライブラリのダウンロードが始まります。最初の1回は時間がかかりますが、2回目以降は<code class="highlighter-rouge">$HOME/.ivy2</code> 以下にダウンロードされたライブラリを使用するので動作が速くなります。</p>
<p>もしメモリの少ないマシンを利用してエラーが出る場合は、以下のように<code class="highlighter-rouge">-mem</code>オプションでメモリ使用量を制限できます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt -mem 512 test # 512 MBのメモリを使用する
</code></pre>
</div>
<p>ダウンロードが終了すると、Scalaコードのコンパイルが始まり、テストコードが実行されます。</p>
<p><img src="http://xerial.org/scala-cookbook/capture/2012-11/scalamin-test.png" alt="scalamin-test" /></p>
<h2 id="フォルダ構成">フォルダ構成</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>./sbt # sbtの実行スクリプト
src/main/scala # ソースコード用のフォルダ
src/test/scala # テストコード用のフォルダ
project # プロジェクトの設定ファイル(プロジェクト名、ライブラリ、プラグイン等の設定)
target # コンパイルされたファイルの置き場(削除しても構わない)
</code></pre>
</div>
<h2 id="scalaのコードを編集する">Scalaのコードを編集する</h2>
<p>Scalaプログラムの入口は<code class="highlighter-rouge">main</code>関数で、以下のように定義されます。</p>
<p><code class="highlighter-rouge">src/main/scala/Hello.scala</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>package scalamin
object Hello {
def main(args:Array[String]) = {
println("Hello World!!")
}
}
</code></pre>
</div>
<p>コマンドラインの引数がargsに渡され、<code class="highlighter-rouge">main</code>のコードが実行されます。<code class="highlighter-rouge">main</code>の中身を書き換えてみましょう。</p>
<h2 id="テストコードを作成し実行する">テストコードを作成し、実行する</h2>
<p>自分で作ったプログラムの動作を確認するために、それを動かすテストコードを作成します。</p>
<p><code class="highlighter-rouge">src/test/scala/HelloTest.scala</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>class HelloTest extends MySpec {
"Hello" should {
"have main" in {
Hello.main(Array.empty)
}
// (その他のテストコードを同様に書いていく)
}
}
</code></pre>
</div>
<p>英語による表記でどのようなテストを実行しているかわかるように書き下せるスタイルになっています。</p>
<ul>
<li>このテストコードでは<a href="http://www.scalatest.org/">ScalaTest</a>ライブラリを使っています。</li>
</ul>
<h3 id="開発しながらテストを繰り返し実行する">開発しながらテストを繰り返し実行する</h3>
<p>プログラミングでは、<code class="highlighter-rouge">テストコードを作成</code> -> <code class="highlighter-rouge">ソースコードを修正</code> -> <code class="highlighter-rouge">コンパイル</code> -> <code class="highlighter-rouge">テストを実行</code>をサイクルとして行います。この支援をする機能が<code class="highlighter-rouge">sbt</code>に備わっています。</p>
<p>以下のようにテストコードを実行します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt "~test"
</code></pre>
</div>
<p>このコマンドはテストコードが実行された後も終了せず、ソースコードの変更があるたびに、コンパイル、テストの実行を行ってくれます。Scalaでの開発時間の短縮に重宝します。</p>
<h3 id="タグ付けしたテストのみを実行">タグ付けしたテストのみを実行</h3>
<p>tagを付けることで特定のテストのみを繰り返し実行できるようになります。</p>
<p><code class="highlighter-rouge">src/test/scala/HelloTest.scala</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>"add a tag to test" taggedAs("test1") in {
debug("test1 is running")
}
</code></pre>
</div>
<p><strong>実行例</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt "~test-only *HelloTest -- -n test1" -Dloglevel=debug
Using C:\Users\leo\.sbt\0.12.0 as sbt dir, -sbt-dir to override.
[info] Loading global plugins from C:\Users\leo\.sbt\0.12.0\plugins
[info] Loading project definition from C:\Users\leo\work\tmp\myproject\project
[info] Set current project to scala-min (in build file:/C:/Users/leo/work/tmp/myproject/)
[HelloTest] test1 is running
[info] HelloTest:
[info] Hello
[info] - should add a tag to test
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 1 s, completed 2012/11/29 12:06:24
1. Waiting for source changes... (press enter to interrupt)
</code></pre>
</div>
<h3 id="特定のクラスにあるテストをすべて実行">特定のクラスにあるテストをすべて実行</h3>
<p>タグ指定せずに以下の用に入力すると、HelloTestクラスの中にあるすべてのテストが繰り返し実行されます。wildcard(<code class="highlighter-rouge">*</code>)が使えます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>./sbt "~test-only *HelloTest"
</code></pre>
</div>
<h2 id="ログを表示する">ログを表示する</h2>
<p>プログラムを開発するときに、変数の内容やどの部分のコードが実行されているかなどの情報をログとして表示できると便利です。IDEでブレークポイントなどを設定しなくてもコードのデバッグがしやすくなります。</p>
<p><code class="highlighter-rouge">HelloTest.scala</code>のテストコード中にログを表示する例があります。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>"display log messages" in {
// To see the log messages higher than the debug level,
// launch test with`./sbt "~test-only *HelloTest" -Dloglevel=debug`
trace("trace log")
debug("debug log")
info("info log")
warn("warning")
error("error")
fatal("fatal error")
}
"display formatted logs" in {
val w = "World"
info(s"Hello $w!!")
info(f"Floating point value: pi = ${math.Pi}%.10f, rad = ${math.toRadians(math.Pi)}%.3e")
}
</code></pre>
</div>
<p><code class="highlighter-rouge">printf</code>などによる表示では、ログを出力するコードを本番用コードで取り除く必要があって大変ですが、<code class="highlighter-rouge">trace</code> < <code class="highlighter-rouge">debug</code> < <code class="highlighter-rouge">info</code> < <code class="highlighter-rouge">warn</code> < <code class="highlighter-rouge">error</code> < <code class="highlighter-rouge">fatal</code> の順にログレベルを分けることで、例えば以下のようにログレベルを設定し、<code class="highlighter-rouge">debug</code>以上のログのみを表示することができます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt "~test" -Dloglevel=debug
</code></pre>
</div>
<p>デフォルトでは<code class="highlighter-rouge">info</code>以上のログが表示される設定になっています。</p>
<ul>
<li>ログの表示には、<a href="https://github.com/xerial/xerial">xerial-core</a> ライブラリにある<code class="highlighter-rouge">Logger</code> traitが使われています。</li>
<li>文字列のformatに関しては<a href="http://xerial.org/scala-cookbook/recipes/2013/01/30/string-interpolation">String interpolation</a>を参考に。</li>
</ul>
<h2 id="コードの実行時間を計測する">コードの実行時間を計測する</h2>
<p>ScalaはJava VM(JVM)の上で動作する言語で、実行時にコード最適化(Just-in-time compile)が行われます。そのためコードの性能は実行順や繰り返し回数などに大きく影響されます。コードの性能を評価する際には、常に実行時間の平均をとり、hot/cold-runかどうかを意識する必要があります。</p>
<h3 id="具体例">具体例</h3>
<p>Scalaではスレッドを使った処理の並列化が容易なので、single coreを使った処理と、multi coreを使った処理の性能を比較してみましょう。以下の例では<code class="highlighter-rouge">time</code>, <code class="highlighter-rouge">block</code>で挟まれたコードブロックを繰り返して実行しています。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>"measure the parallel collection peformance" in {
// Intの配列を作成
val a = Array.ofDim[Int](100000)
(0 until a.length).foreach { i => a(i) = i }
val R = 10
def multiply(e:Int) = e * e
// 全体を10回繰り返して実行する
time("array ops", repeat=10) {
// single-coreで配列の各要素を倍にする。R回実行
block("single-core", repeat=R) {
a.map( multiply )
}
// multi-coreを使って配列の各要素を倍にする。並列化の指示はparを挟むだけ。R回実行
block("multi-core", repeat=R) {
a.par.map( multiply )
}
}
}
</code></pre>
</div>
<p><strong>テストの実行結果 (4 coreのマシンでの例)</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>[HelloTest]
-array ops total:0.705 sec., count: 10, avg:0.071 sec., min:0.049 sec., max:0.159 sec.
-single-core total:0.447 sec., count: 100, avg:0.004 sec., min:0.003 sec., max:0.034 sec.
-multi-core total:0.253 sec., count: 100, avg:0.003 sec., min:0.001 sec., max:0.078 sec.
</code></pre>
</div>
<p>平均してmulti coreのコードが速いが、スレッドを立ち上げるオーバーヘッドがあるので、個々の実行で見ると必ずしも並列化した方が速いとは限らない(実行時間のmaxの値を参照)。</p>
<ul>
<li>実行時間の計測には、<a href="https://github.com/xerial/xerial">xerial-core</a> ライブラリにある<code class="highlighter-rouge">Timer</code> traitが使われています。</li>
</ul>
<h2 id="scalaコードのパッケージを作成する">Scalaコードのパッケージを作成する</h2>
<p>十分にコードをテストできたら本番環境で実行するためのプログラムパッケージを作成します。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt pack
</code></pre>
</div>
<p>このコマンド一つで<code class="highlighter-rouge">target/pack</code>フォルダ内にそのまま配布できる形のパッケージができあがります。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ target/pack/bin/hello
Hello World!!
</code></pre>
</div>
<p><strong>備考</strong></p>
<p>このようなパッケージの作成を手軽にするために、今回sbt用のプラグイン<a href="https://github.com/xerial/sbt-pack">sbt-pack</a>を開発しました。</p>
<h2 id="scalaで作ったコマンドをインストールする">Scalaで作ったコマンドをインストールする</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt pack
$ cd target/pack; make install
</code></pre>
</div>
<p><code class="highlighter-rouge">$HOME/local/bin</code> 以下helloコマンドがインストールされます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ~/local/bin/hello
Hello World!!
</code></pre>
</div>
<ul>
<li>プログラムの名前を変更したい場合は、<code class="highlighter-rouge">project/Build.scala</code>内の<code class="highlighter-rouge">packMain</code>設定を変更してください。</li>
</ul>
<h2 id="intellij-ideaで開発する">IntelliJ IDEAで開発する</h2>
<p>Scalaのプログラムの開発環境(IDE)としては、<a href="http://www.jetbrains.com/idea/">IntelliJ IDEA</a>にScala pluginをインストールして使うのがお薦めです。IntelliJとScala pluginをインストール後、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ ./sbt gen-idea
</code></pre>
</div>
<p>とすると、IntelliJ用のプロジェクトファイルが作成されます。プロジェクトを開くには<code class="highlighter-rouge">File</code>-><code class="highlighter-rouge">Open</code>で、今回作成したmyprojectフォルダを選択します。</p>
<ul>
<li>参考 <a href="http://xerial.org/scala-cookbook/recipes/2012/06/27/scala-quick-start">IntelliJ (Scala開発に使えるIDE) のセットアップ</a></li>
</ul>
<h2 id="もっと学びたい人は">もっと学びたい人は</h2>
<ul>
<li><a href="http://xerial.org/scala-cookbook/recipes/2012/06/28/grammar">Scalaの文法</a></li>
<li><a href="http://xerial.org/scala-cookbook/recipes/2012/06/28/using-scala-collections">Scalaのコレクションを使う</a></li>
<li><a href="http://xerial.org/scala-cookbook">Scala Cookbook</a>には、Scalaの開発でつまづきやすい点についてのヒントがあります。</li>
<li><a href="http://xerial.org/scala-cookbook/recipes/2012/06/28/scala-references">Scalaを学ぶ</a> - Scalaを学ぶのにおすすめの資料をまとめてあります。</li>
</ul>
Gitでの開発の流れを理解する
2012-11-16T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/11/16/git-flow
<p>Gitを効率的に使うには、以下の役割をもつbranchを作ると良いことが経験的に知られてきています。</p>
<ul>
<li>新しい機能の追加のための<strong>feature</strong> branchを作成し、他の機能の更新と衝突させない</li>
<li>featureで作成した新しい機能を取り込んでいく<strong>develop</strong> branch</li>
<li>安定版(<strong>master</strong> branch)を作成する準備のための<strong>release</strong> branch</li>
<li>ビルドでき安定して動く状態を保持する <strong>master</strong> branch</li>
<li>安定板に対する修正の<strong>hotfix</strong> branch</li>
</ul>
<p><img src="http://xerial.org/scala-cookbook/capture/2012-11/gitflow.png" alt="gitflow" /></p>
<p>詳細は以下の記事を読むと良いでしょう。Gitのコマンドの使い方と共に、開発の流れを覚えられます。</p>
<ul>
<li><a href="http://keijinsonyaban.blogspot.jp/2010/10/successful-git-branching-model.html">A successful Git branching model (日本語訳)</a></li>
</ul>
Remote branchを削除する
2012-11-16T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/11/16/deleteremotebranch
<div class="highlighter-rouge"><pre class="highlight"><code># localでブランチを削除
git branch -d <branch name>
# remoteブランチを削除
git push :<branch name>
# git 1.7 以上は以下のコマンドでリモートブランチを削除できる
git push origin --delete <branch name>
</code></pre>
</div>
<p>2013年現在、GitHubではweb上でリモートブランチを削除する機能が追加されています。</p>
<h3 id="参考">参考</h3>
<p><a href="http://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-both-locally-and-in-github">How do I delete a Git branch both locally and in Github? - stackoverflow</a></p>
Eitherによるエラー処理
2012-11-16T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/11/16/either
<p>エラー処理によるコードの分岐を減らしたい場合、Eitherを使うとよい。</p>
<h2 id="eitherの使い方">Eitherの使い方</h2>
<p><a href="http://www.scala-lang.org/api/current/index.html#scala.Either"><code class="highlighter-rouge">Either[A, B]</code></a> は、<code class="highlighter-rouge">A</code>または<code class="highlighter-rouge">B</code>を返す型である。</p>
<p>Eitherは通常<code class="highlighter-rouge">Either[(エラー情報), (結果)]</code>の形で使われる。例えばデータ処理が成功した場合はその結果を用いて引き続きの処理を行いたいが、エラーの場合は何もせず次のコードにエラーだけを伝えたい場合がある。</p>
<p>Eitherから値を取り出すには、left, rightの値に対してmap, flatMapなどを用いる。例えば、<code class="highlighter-rouge">Either.right map { ... }</code>とすると、値の内容が<code class="highlighter-rouge">Right</code>型の場合はmap内の関数を適用し、<code class="highlighter-rouge">Left</code>の型の場合はmapの処理を無視して<code class="highlighter-rouge">Left</code>の内容(この場合はエラー情報を)をそのまま返す。</p>
<h3 id="具体例">具体例</h3>
<div class="highlighter-rouge"><pre class="highlight"><code># 文字列がIntに変換できるならIntを、失敗した場合はExceptionを返す関数
scala> def parseInt(s:String) : Either[Exception, Int] =
try Right(s.toInt) catch { case e:Exception => Left(e) }
Parseint: (s: String)Either[Exception,Int]
# Intへの変換が成功。Rightを返す
scala> parseInt("128")
res5: Either[Exception,Int] = Right(128)
# 変換できない場合はLeftを返す
scala> parseInt("234A")
res6: Either[Exception,Int] = Left(java.lang.NumberFormatException: For input string: "234A")
# 値を取りだしてFloatに変換
scala> parseInt("49").right map { _.toFloat }
res8: Product with Serializable with Either[Exception,Float] = Right(49.0)
# 結果がLeft(Exception)の場合は、toFloatは実行されずに、Exceptionを伝播する
scala> parseInt("ADF").right map { _.toFloat }
res9: Product with Serializable with Either[Exception,Float] = Left(java.lang.NumberFormatException: For input string: "ADF")
# Left(Exception)であれば、その内容を表示(getMessage)
scala> parseInt("ADF").left map { _.getMessage }
res11: Product with Serializable with Either[java.lang.String,Int] = Left(For input string: "ADF")
# 結果がRightの場合は、getMessageは実行されない
scala> parseInt("40").left map { _.getMessage }
res12: Product with Serializable with Either[java.lang.String,Int] = Right(40)
</code></pre>
</div>
<p>Eitherを使うことで、エラーを含んだデータであっても処理の流れを妨げないようにできる。</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="http://xerial.org/scala-cookbook/recipes/2012/07/18/wig">WIGファイルの構文解析</a> Eitherを使ったより具体的なコード例として</li>
</ul>
塩基を表すクラスを定義する
2012-11-16T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/11/16/dna
<p>DNAの塩基を表すクラスを作成したい。</p>
<h2 id="コード例">コード例</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>// companion object
object DNA {
// objectで定義するとsingletonになるのでメモリの節約に
object A extends DNA(0)
object C extends DNA(1)
object G extends DNA(2)
object T extends DNA(3)
object N extends DNA(4) // NはA, C, G, Tのどれかを表す
// DNAの文字列をすべて並べる。
val values = Array(A, C, G, T, N)
// 用途によって別の集合を定義することもできる。N以外の塩基
val exceptN = Array(A, C, G, T)
private val codeTable = Array(A, C, G, T, N, N, N, N)
def complement(code:Int) : DNA = codeTable((~code & 0x03) | (code & 0x04))
}
// DNAクラス
sealed abstrat class DNA(val code:Int) {
// object名(最後に$マークが付くので除く)をenum名として使う
val name = this.getClass.getSimpleName.replaceAll("""\$""", "")
override def toString = name
// DNAクラスには自由にメソッドを定義できる
def complement = DNA.complement(code)
}
</code></pre>
</div>
<p>このように定義すると、パターンマッチが問題なく使えるし、complementなど機能を充実させることもできる。</p>
<p>クラス定義に<code class="highlighter-rouge">sealed</code>を付けると、DNAを拡張したクラスは同一ファイル内でしか定義できなくなる。さらに<code class="highlighter-rouge">abstract</code>クラスにすると、DNAを拡張したクラスはA, C, G, T, N以外にないことも保証できるので、match文をexhaustive(すべての場合を網羅する状態)にできる。</p>
<h3 id="パターンマッチの例">パターンマッチの例</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>import DNA._
val l = G
l match {
case A => ...
case C => ...
case G => ...
case T => ...
case N => ...
}
</code></pre>
</div>
<h3 id="練習問題">練習問題</h3>
<p>DNA配列を表す<code class="highlighter-rouge">DNASeq</code>などを定義する際に上記の<code class="highlighter-rouge">DNA</code>クラスが役立つ。実際に以下のような<code class="highlighter-rouge">DNASeq</code>traitの機能をもつDNAの配列のクラスを作成してみよう。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>trait DNASeq {
def length : Int
def apply(index:Int) : DNA
def reverseComplement : DNASeq
}
// DNA (A, C, G, T)を2bitで表現したDNASeqの実装
class DNASeq2bit(seq:Array[Long], val length:Int) extends DNASeq {
....
}
</code></pre>
</div>
<h2 id="参考">参考</h2>
<p>より詳細な実装は以下のコードを参考にしてください。</p>
<ul>
<li>DNAクラス <a href="https://github.com/xerial/genome-weaver/blob/develop/lens/src/main/scala/utgenome/weaver/lens/DNA.scala">DNA.scala</a></li>
<li>2bitで塩基(A, C, G, T)を表現した配列 <a href="https://github.com/xerial/genome-weaver/blob/develop/lens/src/main/scala/utgenome/weaver/lens/ACGTSeq.scala">ACGTSeq.scala</a></li>
<li>3bitで塩基(A, C, G, T, N)を表現した配列 <a href="https://github.com/xerial/genome-weaver/blob/develop/lens/src/main/scala/utgenome/weaver/lens/ACGTNSeq.scala">ACGTNSeq.scala</a></li>
</ul>
<p>塩基配列をビット列で表現すると、配列中にAが何個含まれるかなどの計算が高速に行なえるようになり(popCount)、FM-Indexによるアラインメントの計算等が高速化できます。</p>
<p>IUPACコードなども同様に実装できます。<a href="https://github.com/xerial/genome-weaver/blob/develop/lens/src/main/scala/utgenome/weaver/lens/IUPAC.scala">IUPAC.scala</a></p>
0 until 100 - 数字の範囲を指定する
2012-08-31T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/08/31/range
<h2 id="0-until-100の裏側">0 until 100の裏側</h2>
<p>0 until 100 (exclusive), 0 to 100 (inclusive) とはいったい何か? <a href="http://www.scala-lang.org/api/current/index.html#scala.Int">scala.Int</a>の定義を見ても、until, toの関数定義は見当たらない。実際には、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>0 until 100
-> 0.until(100) // Scalaでは関数適用時の.と括弧が省略できる
-> RichInt(0).until(100) // 0:Int -> RichInt(0) への変換
</code></pre>
</div>
<p>の流れでIntから<a href="http://www.scala-lang.org/api/current/index.html#scala.runtime.RichInt">RichInt</a>への変換が行われ、Range(0, 100)が生成されている。</p>
<p>Scalaではすべてのコードに対して<a href="http://www.scala-lang.org/api/current/index.html#scala.Predef$">scala.Predef</a>に定義されている関数がincludeされている。ドキュメントをたどっていくと以下の定義が見つかる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>implicit def intWrapper(x:scala.Int) : scala.runtime.RichInt
</code></pre>
</div>
<p>これはimplicit converstionと呼ばれる。Scalaコンパイラは賢く、Intにuntilというメソッドの定義がない場合、Intに対してimplicit conversionを適用すれば、until関数が使えるかどうかまでをチェックしてくれる。変換して関数が使える場合、implicit conversionが適用され、プログラマが明示的に変換コードを書く手間が軽減される。つまり、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>RichInt(0).until(100)
</code></pre>
</div>
<p>と書かなくても良い。</p>
for-comprehensionの展開
2012-08-31T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/08/31/for-comprehension
<h2 id="for-comprehensionの定義">for-comprehensionの定義</h2>
<p>Scalaのfor文(for-comprehension: for文による網羅) は、C言語のようにループを回しているわけではなく、map, flatMapなどの関数を呼び出すsyntax sugarとなっています。以下にScalaのfor文の置き換えの定義を示します。</p>
<h3 id="for内のパラメータが1つの場合">for内のパラメータが1つの場合</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>for { p0 <- e0 } yield e
</code></pre>
</div>
<p>は、mapを使って以下に置き換えられます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>e0 map { p0 => e }
</code></pre>
</div>
<h3 id="複数パラメータがある場合">複数パラメータがある場合</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>for {
p0 <- e0
p1 <- e1
...
pn <- en } yield e
</code></pre>
</div>
<p>一番外側のパラメータがflatMapに置き換えられます。これが再帰的に繰り返され、パラメータが残り1つになると、最初のルールを使ってmapが適用されます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> e0.flatMap { p0 =>
for {
p1 <- e1
p2 <- e2
...
pn <- en
} yield e
}
</code></pre>
</div>
<p>例えば、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>for(p0 <- e0; p1 <- e1; p2 <- e2) yield (p0, p1, p2)
</code></pre>
</div>
<p>は、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>e0.flatMap(p0 => e1.flatMap(p1 => e2.map(p2 => (p0, p1, p2))))
</code></pre>
</div>
<p>と同じになります。</p>
共変 covariant な型を使う
2012-08-15T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/08/15/covariant
<p>Scalaのコレクションクラス(List, Seqなど)は、<code class="highlighter-rouge">List[+A]</code>と型名の前に+を付けてcovariant(共変)な型を許すように定義されています。covariantとは、Aのクラスを拡張したクラスBがあれば、List[B]はList[A]として代入できることを意味します。例えば以下のように、クラス階層を定義したときに、List[Cat]をList[Animal]として代入できます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> abstract class Animal
case class Cat(name:String) extends Animal
case class Dog(name:String) extends Animal
val c : List[Cat] = List(Cat("A"), Cat("B"))
// ListはList[+A]として定義されている
val a : List[Animal] = c // OK.
// List[+A]はcovariantなので、List[B <: A](Aクラスから派生したクラスのList)を代入できる
</code></pre>
</div>
<p>また、List[Cat]とList[Dog]を足し合わせて、List[Animal]を作ることもできます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> val l : List[Animal] = Dog("D") :: c // OK. List(Dog(D), Cat(A), Cat(B))
</code></pre>
</div>
<h2 id="optionクラスでのcovariantの利用">Optionクラスでのcovariantの利用</h2>
<p>Optionも、covariantを使ってOption[+A]として定義されており、NoneはOption[Nothing]から拡張して定義されています。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object None extends Option[Nothing] {
def map[B](f: Nothing => B) : Option[B] = None
def flatMap[B](f: Nothing => Monad[B]) : Option[B] = None
}
</code></pre>
</div>
<p>Nothingはあらゆる型の子(subtype)になれるようにScalaで定義されているので、None、すなわちOption[Nothing]は、Option[A]やOption[B]などに代入できます。この工夫により、None[A], None[B]などと宣言する必要はなく、Noneとだけコード中に書くだけで済むようになっています。</p>
Option Monad
2012-08-15T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/08/15/option
<p><a href="http://www.scala-lang.org/api/current/index.html#scala.Option">Option</a> を使いこなすと、より関数型言語らしいコードが書けるようになります。</p>
<h2 id="どんなときに使うのか">どんなときに使うのか?</h2>
<ul>
<li><code class="highlighter-rouge">null</code>の代わりに使う
<ul>
<li>関数の結果が得られない場合など (例:<code class="highlighter-rouge">Map[K,V]#get(key)</code>の返り値は <code class="highlighter-rouge">Option[V]</code>)</li>
</ul>
</li>
<li>モナド(monad)として使い、エラー値を扱うコードの流れをスムーズにする
<ul>
<li>for-comprehensionと共に使うと良い</li>
</ul>
</li>
</ul>
<p>モナドと聞いて怖じ気付く必要はありません。これから詳しく説明していきます。</p>
<h3 id="パターンマッチでoptionの値を取得">パターンマッチでOptionの値を取得</h3>
<p>Option[A]は値が存在するか、しないかを表すクラスで、Some(a)とNoneの二種類の値があります。パターンマッチでこの二種類の値を処理するのが基本です。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> val m = Map("A" -> "Apple", "B" -> "Banana")
def lookup(symbol:String) = m.get(symbol) match { // m.get でOption[String]が返る
case Some(name) => name + " is found!"
case None => "No name is found for " + symbol
}
println(lookup("A")) // Apple is found
println(lookup("C")) // No name is found for C
</code></pre>
</div>
<h3 id="パターンマッチをせずにoptionを処理する">パターンマッチをせずにOptionを処理する</h3>
<p>Optionの値がSome(a)の時だけ続きの処理を行うには<code class="highlighter-rouge">map</code>を使います。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> val m = Map("A" -> "Apple", "B" -> "Banana")
m.get("A") map { f => println(f + "is found") } // Apple is found
m.get("C") map { f => println(f + "is found") } // (何も表示されない)
</code></pre>
</div>
<h3 id="その他便利な関数">その他便利な関数</h3>
<p><em>getOrElse</em> - Optionの値がSome(v)ならvを、それ以外にはdefault値を返す</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def getOrElse[B >: A](default: ⇒ B): B
</code></pre>
</div>
<p>使い方</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val v = List(Some("A"), None)
for(each <- v) yield { each.getOrElse("empty") } // List(A, empty)
</code></pre>
</div>
<p>Optionには、map, filter, foreachなどcollectionでよく使う関数も定義されており、これらもやはり値がSome(x)の場合のみ処理が実行されるように定義されています。詳しくは<a href="http://www.scala-lang.org/api/current/index.html#scala.Option">OptionのAPI</a>を参照してください。</p>
<h2 id="エラー処理にoptionを使う">エラー処理にOptionを使う</h2>
<p>まず例題を示します。</p>
<h3 id="例入力がnullかどうかをチェックする">例:入力がnullかどうかをチェックする</h3>
<p>例えば、ユーザー名とパスワードを受け取ってログインする関数<code class="highlighter-rouge">login</code>を作ることを考えます。ユーザー名とパスワードの情報が揃っていないと次の処理ができないので、nullかどうかのチェックが入りますが、以下のように、コードが入り組んでしまいます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def login(name:String, password:String) : Boolean = {
if(name != null) {
if(password != null)
database.isValidPassword(name, password)
else
false
}
else
false
}
</code></pre>
</div>
<h4 id="early-exitを利用したコード">Early exitを利用したコード</h4>
<p>あまりScala的ではないですが、事前にnullかどうかをチェックしてデータに不備があれば早々にreturn(early exit)しる書き方も、C, Javaなどのプログラミング言語でよく使われています。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def login(name:String, password:String) : Boolean = {
if(name == null)
return false
if(password == null)
return false
return database.isValidPassword(name, password)
}
</code></pre>
</div>
<p>ただし、不備のあった場合の処理(falseを返すコード)が重複して現れてしまうので無駄があります。</p>
<h4 id="パターンマッチを利用したコード">パターンマッチを利用したコード</h4>
<p>事前に<code class="highlighter-rouge">Option(v)</code>として値をラップしておくと、vがnullの場合はNone, それ以外の場合はSome(v)に変換してくれます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def login(name:String, password:String) : Boolean = (Option(name), Option(password)) match {
case (Some(u), Some(p)) => database.isValidPassword(u, p)
case _ => false
}
</code></pre>
</div>
<p>ここでパターンマッチを利用するのもありです。</p>
<p>大分コードがすっきりしてきましたが、ユーザー名が与えられていない場合、そこで処理を終了してほしいのですが、上記のコードではパスワードの方も常にSome(p)かどうかを判定しているので無駄がありそうです。</p>
<h2 id="モナドmonadとは">モナド(monad)とは</h2>
<p>コードをきれいにしつつ、処理の無駄も省くのに登場するのがモナドです。</p>
<p>ScalaのOptionはモナドになっています。モナドはとりあえずmap, flatMapの二種類の関数が定義されているものと理解すればよいでしょう。少なくともこの理解だけですぐに使い始めることができます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>trait Monad[A] {
// Monad[A]の中身Aを取り出し、fを適用して、その結果BをMonad[B]でwrapする
def map[B](f: A => B) : Monad[B]
// Monad[A]の中身Aを取り出し、Monadを返すfを適用する
def flatMap[B](f: A => Monad[B]) : Monad[B]
}
</code></pre>
</div>
<p>(実際にこのような単体のMonad traitがあるわけではありませんが、同等のものがScala標準ライブラリの中には存在します)</p>
<p>Monadは値をくるむ毛皮のようなもので、map, flatMapはその毛皮を剥がしてから何かの操作を行い、その結果に対してまた毛皮を着せる操作に対応しています。Monadを使ったコードでは、中に含まれている値に対して何らかの操作を行っても、Monad[A] からMonad[Monad[B]]のようなネストした型に変換するのではなく、Monad[A] -> Monad[B]と毛皮を一枚で済ませるようにするのが特徴です。</p>
<h3 id="optionはmonad">OptionはMonad</h3>
<p>ScalaのOptionがmonadになっていると言いましたが、では実際にOptionの実装の一部を簡単にしたものを取り出して見てみましょう。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>sealed trait Option[A] {
def map[B](f: A => B) : Option[B]
def flatMap[B](f: A => Monad[B]) : Option[B]
}
case class Some[A](a: A) extends Option[A] {
def map[B](f: A => B) : Option[B] = Some(f(a))
def flatMap[B](f: A => Monad[B]) : Option[B] = f(a)
}
case class None[A] extends Option[A] {
def map[B](f: A => B) : Option[B] = None
def flatMap[B](f: A => Monad[B]) : Option[B] = None
}
</code></pre>
</div>
<p>map, flatMapは、Someの中身の値<code class="highlighter-rouge">a</code>に対して実行されますが、Noneの場合、中身がないので、map, flatMapは共に実行結果としてNoneが返ります。ここで注目しておきたいのは、Noneに対してもmap, flatMapが定義されているので、map, flatMapの操作は、Optionの値がSomeであろうとNoneであろうと連続して適用していけるという点です。</p>
<ul>
<li>上記のNoneクラスは型情報を簡略化した定義になっています。Noneの厳密な定義については、<a href="http://xerial.org/scala-cookbook/recipes/2012/08/15/covariant">共変 covariantな型を使う</a>を参考に。</li>
</ul>
<h3 id="monadのmap-flatmapを使う">Monadのmap, flatMapを使う</h3>
<p>if文やパターンマッチを使ったnull(またはNone)の値のチェックは、ログインをするためのコードの本質的な部分ではないので、本来はエラー処理の部分を気にせずプログラミングできることが好ましいはずです。ここでmonadのmap, flatMapを使うとコードの流れを妨げずに、必要な処理に的を絞ってコードを書けるようになります。以下はその例です。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def login(name:Option[String], password:Option[String]) : Boolean =
name flatMap { u => password map { p => database.isValidPassword(u, p) } } getOrElse false
</code></pre>
</div>
<p>nameやpasswordがNoneの場合、map, flatMapの適用結果はNoneになるだけなので、コード中に出てくるエラー処理は最後のgetOrElseの部分のみになり、残りはエラー処理を気にせずに一本道で書けます。</p>
<p>コメントを挟んで、コードの中身をより詳しく説明すると以下のようになります。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def login(name:Option[String], password:Option[String]) : Boolean = {
val r = name flatMap { u => // name monadの中身がとりだされる
password map { p => // password monadの中身が取り出される
database.isValidPassword(u, p)
} // mapなので、monadを外したBooleanが返る
}
// rの型はbooleanをmonadでくるんだ Option[Boolean]
r getOrElse false // getOrElseもmonadを剥がす。
</code></pre>
</div>
<p>ただし、map, flatMapを活用すると、コードは一行に収まるもののやや面倒な書き方になってしまうのが玉に瑕です。</p>
<h3 id="for-comprehensionを使って簡潔に">for-comprehensionを使って簡潔に</h3>
<p>そこでScalaのfor文による網羅(for-comprehension)を使うと、上記のコードを手短に書けるようになります。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def login(name:Option[String], password:Option[String]) : Boolean =
val r = for(u <- name; p <- password) yield database.isValidPassword(u, p)
r getOrElse false // user, passの情報が揃って無い場合にはfalseが返る
</code></pre>
</div>
<p>これがどうmonadなのか不思議に思うのは当然ですが、for-comprehensionが具体的に何をしているのかを知れば納得できるはずです。</p>
<h3 id="for-comprehensionの定義">for-comprehensionの定義</h3>
<p>Scalaのfor-comprehensionは、map, flatMapなどmonadによる操作を簡潔に使うためのsyntax sugarとなっています。以下に置き換えの定義を示します。</p>
<h4 id="for内のパラメータが1つの場合">for内のパラメータが1つの場合</h4>
<div class="highlighter-rouge"><pre class="highlight"><code>for { p0 <- e0 } yield e
</code></pre>
</div>
<p>は、mapを使って以下に置き換えられます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>e0 map { p0 => e }
</code></pre>
</div>
<h4 id="複数パラメータがある場合">複数パラメータがある場合</h4>
<div class="highlighter-rouge"><pre class="highlight"><code>for {
p0 <- e0
p1 <- e1
...
pn <- en } yield e
</code></pre>
</div>
<p>一番外側のパラメータがflatMapに置き換えられます。これが再帰的に繰り返され、最後に上記のパラメータが1つの場合のルールによりmapが適用されます。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> e0.flatMap { p0 =>
for {
p1 <- e1
p2 <- e2
...
pn <- en
} yield e
}
</code></pre>
</div>
<p>これらの変換を適用すると、先に述べたfor文によるlogin関数のコードがmap, flatMapで置き換えたものと同等になることを確認してください。</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="http://www.youtube.com/watch?v=Mw_Jnn_Y5iA">Scala Monads: Declutter You Code With Monadic Design</a> 英語のチュートリアルですが、わかりやすくて良いです</li>
</ul>
複数行に渡る文字列を作成する
2012-08-02T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/08/02/multiline-string
<p>改行を含む文字列をソースコード中に埋め込むには、triple quote(<code class="highlighter-rouge">"""</code>)を使う。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val s = """Hello World!
Hello Scala!"""
</code></pre>
</div>
<p>コード中で読みやすいようにインデントを揃えたい場合には、stripMarginを使うと良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val s2 = """|HelloWorld!
|Hello Scala!""".stripMargin
</code></pre>
</div>
<p>上記のsとs2は同じ内容の文字列になる。</p>
gpgでsbtプロジェクトに署名する
2012-08-02T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/08/02/gpg
<p><a href="https://github.com/sbt/xsbt-gpg-plugin/">xsbt-gpg-plugin</a>を使うと、sbtで生成されたプロジェクトのjarファイルにGnuPG(gpg)による署名ができる。<a href="https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide">Sonatypeのリポジトリにプロジェクトをdeployする</a>際にgpgによる署名が必須。作成したプログラムをSonatypeのリポジトリに登録して、Maven Central Repositoryに同期してもらうと、自分で作ったプログラムを世界中の人に手軽にダウンロードできる状態(つまりsbtのlibraryDependenciesの設定に追加するだけで使える状態)で公開できる。</p>
<ul>
<li><a href="http://www.scala-sbt.org/using_sonatype.html">Deplying to Sonatype</a>
<ul>
<li>Scala+SBTでpgpによる署名を施してSonatypeのリポジトリにプロジェクトをアップロードする方法</li>
</ul>
</li>
</ul>
<h2 id="必要なツール">必要なツール</h2>
<p>gpg, gpg-agent, keychain</p>
<ul>
<li>以下の内容は、Windows+cygwin環境ではgpg-agentをうまく動かす方法が見当たらないため、まだ成功していない。MacかLinuxを使うと吉。</li>
</ul>
<h2 id="設定">設定</h2>
<p><code class="highlighter-rouge">~/.sbt/(sbt-version)/plugins/build.sbt</code>に<a href="https://github.com/sbt/sbt-pgp/">sbt-pgp-plugin</a>を追加:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>addSbtPlugin("com.typesafe.sbt" % "pgp-plugin" % "0.7")
</code></pre>
</div>
<p><code class="highlighter-rouge">~/.sbt/(sbt-version)/gpg.sbt</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>// useGpg, useGpgAgentをtrueに設定
useGpg := true
useGpgAgent := true
</code></pre>
</div>
<p><code class="highlighter-rouge">useGpgAgent</code>はfalseに設定して、<code class="highlighter-rouge">$HOME/.gnupg/gpg.conf</code> 内で、<code class="highlighter-rouge">use-agent</code>を設定しても良い。</p>
<h3 id="参考-gpgconfの設定">参考: gpg.confの設定</h3>
<p><code class="highlighter-rouge">$HOME/.gnupg/gpg.conf</code>(抜粋)
# We support the old experimental passphrase agent protocol as well as
# the new Assuan based one (currently available in the “newpg” package
# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent,
# you have to run an agent as daemon and use the option</p>
<div class="highlighter-rouge"><pre class="highlight"><code># 以下をコメントアウトする
use-agent
</code></pre>
</div>
<h3 id="お薦めしない方法">お薦めしない方法</h3>
<p>Windowsではgpg-agentが使えないため、gpgを使う替わりに以下の設定でパスフレーズの入力を省けるようになるが、危険なのであまりお薦めしない。</p>
<p><code class="highlighter-rouge">~/.sbt/(sbt-version)/gpg.sbt</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>pgpPassphrase = Some(Array('g','p','g','p','a','s','s')
</code></pre>
</div>
<h2 id="gpgの証明書の作成と登録">gpgの証明書の作成と登録</h2>
<div class="highlighter-rouge"><pre class="highlight"><code># 鍵の作成
$ gpg --gen-key
(名前、e-mail, パスフレーズなどを登録)
# 鍵の表示
$ gpg --list-keys
pub XXXXX/YYYYYYYY 2012-08-82
# 鍵を公開サーバーに登録
$ gpg --send-keys YYYYYYYY
</code></pre>
</div>
<ul>
<li><code class="highlighter-rouge">gpg --gen-key</code>の際にmissing entropyと言われてフリーズする状態(sshでログインした環境で作業すると起こる)になった場合は、同じマシンで別のシェルを開いて、ls -lR /. などディスクにアクセスするコマンドを実行すれば良いとのこと。</li>
</ul>
<h2 id="gpg-agentの設定">gpg-agentの設定</h2>
<p>gpg-agentを使うと、パスフレーズの入力を最初の一回だけ行えば、以降のパスフレーズの入力はgpg-agentが代わりにやってくれるようになる。keychainを使ってログイン時にgpg-agentを呼び出すこともでき、gpg-agentの多重起動を防ぐことができる。</p>
<p>ログイン時にgpg-agentを立ち上げるには、<code class="highlighter-rouge">.bash_profile</code>, <code class="highlighter-rouge">.zprofile</code>などに以下の記述を追加する。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>keychain -q --agents gpg
[ -z "$HOSTNAME" ] && HOSTNAME=`uname -n`
[ -f $HOME/.keychain/$HOSTNAME-sh-gpg ] && \
. $HOME/.keychain/$HOSTNAME-sh-gpg
</code></pre>
</div>
<h3 id="パスフレーズの時間">パスフレーズの時間</h3>
<p>デフォルトでgpg-agentがパスフレーズを覚えてくれる時間は600秒と短いので、長めに設定しておくと日常のビルドが楽になる。</p>
<p><code class="highlighter-rouge">$HOME/.gnupg/gpg-agent.conf</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code># パスフレーズをcacheする時間を36000秒に設定
default-cache-ttl 360000
max-cache-ttl 360000
use-standard-socket
</code></pre>
</div>
<h2 id="署名付きプロジェクトのビルド">署名付きプロジェクトのビルド</h2>
<div class="highlighter-rouge"><pre class="highlight"><code># $HOME/.ivy2以下にインストール
$ sbt publish-local
# sbtのsettingsでpublishToで指定した先に署名付きjarファイルをアップロード
$ sbt publish
</code></pre>
</div>
<p>passphraseを聞かれてエラーが出てしまう場合、適当なファイルをgpgコマンドでエンコードしてagentにパスフレーズを覚えさせてからpublishを実行するとよい。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ touch /tmp/hello
$ gpg /tmp/hello
(パスフレーズを入力)
</code></pre>
</div>
WIGファイルを構文解析する
2012-07-18T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/18/wig
<h2 id="解説">解説</h2>
<p><a href="http://genome.ucsc.edu/goldenPath/help/wiggle.html">WIGフォーマット</a>は、ゲノム座標上に数値データを載せるときに使われる。このデータは一次元の大きな配列を表現しているのだが、その他のアノテーション(データを説明するメタデータ、グラフデータの幅、ステップの量など)も適切に処理する必要がある。</p>
<h3 id="wigフォーマットのサンプル">WIGフォーマットのサンプル</h3>
<p><a href="http://genome.ucsc.edu/goldenPath/help/wiggle.html">http://genome.ucsc.edu/goldenPath/help/wiggle.html</a>より。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>browser position chr19:49304200-49310700
browser hide all
# 150 base wide bar graph at arbitrarily spaced positions,
# threshold line drawn at y=11.76
# autoScale off viewing range set to [0:25]
# priority = 10 positions this as the first graph
# Note, one-relative coordinate system in use for this format
track type=wiggle_0 name="variableStep" description="variableStep format" visibility=full autoScale=off viewLimits=0.0:25.0 color=50,150,255 yLineMark=11.76 yLineOnOff=on priority=10
variableStep chrom=chr19 span=150
49304701 10.0
49304901 12.5
49305401 15.0
49305601 17.5
49305901 20.0
49306081 17.5
49306301 15.0
49306691 12.5
49307871 10.0
# 200 base wide points graph at every 300 bases, 50 pixel high graph
# autoScale off and viewing range set to [0:1000]
# priority = 20 positions this as the second graph
# Note, one-relative coordinate system in use for this format
track type=wiggle_0 name="fixedStep" description="fixedStep format" visibility=full autoScale=off viewLimits=0:1000 color=0,200,100 maxHeightPixels=100:50:20 graphType=points priority=20
fixedStep chrom=chr19 start=49307401 step=300 span=200
1000
900
800
700
600
500
400
300
200
100
</code></pre>
</div>
<h2 id="方法">方法</h2>
<p>Scalaのparser combinatorを使った構文解析を行う。</p>
<h3 id="サンプルコード">サンプルコード</h3>
<p><a href="https://github.com/xerial/genome-weaver/blob/develop/lens/src/main/scala/utgenome/weaver/lens/WIG.scala">Wig.scala</a> (<a href="https://github.com/xerial/genome-weaver/">Genome Weaverプロジェクト</a>より)</p>
<h3 id="wigフォーマットの各行に対応するクラスを定義">WIGフォーマットの各行に対応するクラスを定義</h3>
<p><a href="http://genome.ucsc.edu/goldenPath/help/wiggle.html">WIG format</a>は一行ずつ解析できる仕様になっており、各々の行に対応するクラスを定義する。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object WIG {
sealed abstract class Header extends WIG
case class Comment(line: String) extends WIG
case class Browser(line: String) extends Header
case class Track(property: Map[String, String]) extends Header
case class VariableStep(chrom: String, span: Int = 1) extends Header
case class FixedStep(chrom: String, start: Int, step: Int = 1, span: Int = 1) extends Header
sealed abstract class Data extends WIG
case class VariableStepValue(position: Int, value: Float) extends Data
case class FixedStepValue(value: Float) extends Data
case class Error(message:String) extends WIG
}
sealed abstract class WIG
</code></pre>
</div>
<h4 id="構文解析の結果">構文解析の結果</h4>
<p>上記のサンプルデータから以下のような出力を得たい:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>Browser(browser position chr19:49304200-49310700)
Browser(browser hide all)
Comment(# 150 base wide bar graph at arbitrarily spaced positions,)
Comment(# threshold line drawn at y=11.76)
Comment(# autoScale off viewing range set to [0:25])
Comment(# priority = 10 positions this as the first graph)
Comment(# Note, one-relative coordinate system in use for this format)
Track(Map(yLineMark -> 11.76, name -> variableStep, priority -> 10, autoScale -> off, description -> variableStep format, color -> 50,150,255, yLineOnOff -> on, viewLimits -> 0.0:25.0, type -> wiggle_0, visibility -> full))
VariableStep(chr19,150)
VariableStepValue(49304701,10.0)
VariableStepValue(49304901,12.5)
VariableStepValue(49305401,15.0)
VariableStepValue(49305601,17.5)
VariableStepValue(49305901,20.0)
VariableStepValue(49306081,17.5)
VariableStepValue(49306301,15.0)
VariableStepValue(49306691,12.5)
VariableStepValue(49307871,10.0)
Comment(# 200 base wide points graph at every 300 bases, 50 pixel high graph)
Comment(# autoScale off and viewing range set to [0:1000])
Comment(# priority = 20 positions this as the second graph)
Comment(# Note, one-relative coordinate system in use for this format)
Track(Map(name -> fixedStep, priority -> 20, autoScale -> off, description -> fixedStep format, color -> 0,200,100, viewLimits -> 0:1000, maxHeightPixels -> 100:50:20, type -> wiggle_0, visibility -> full, graphType -> points))
FixedStep(chr19,49307401,300,200)
FixedStepValue(1000.0)
FixedStepValue(900.0)
FixedStepValue(800.0)
FixedStepValue(700.0)
FixedStepValue(600.0)
FixedStepValue(500.0)
FixedStepValue(400.0)
FixedStepValue(300.0)
FixedStepValue(200.0)
FixedStepValue(100.0)
</code></pre>
</div>
<h3 id="正規表現による字句解析lexical-analysis">正規表現による字句解析(lexical analysis)</h3>
<p><a href="http://www.scala-lang.org/api/current/index.html#scala.util.parsing.combinator.RegexParsers"><code class="highlighter-rouge">RegexParser</code></a> を使うと手軽に正規表現を使った構文解析が行える。 空白文字(white spaces)はデフォルトで無視してくれるのでルール中に記述する必要はない。</p>
<p>WIGフォーマットの要素をBNF記法で表すと、以下のようになる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>header := paramName param*
param := paramName "=" paramValue
paramName := [A-Za-z0-9:\-_\.]
paramValue := stringLiteral | quote | value
value := [^\"\s]+
stringLiteral := '"' (.*) '"' // 単純表記。実際に使うパターンは以下のコード例を参照
quote := "'" (.*) "'" // 単純表記。実際に使うパターンは以下のコード例を参照
</code></pre>
</div>
<p>この文法に対応する解析構文を行うには、<code class="highlighter-rouge">Parse[A]</code>の型を返す要素(elem)をparser内に定義する。正規表現(文字列から<code class="highlighter-rouge">.r</code>で作成される) を記述すると、implicit conversionによって<code class="highlighter-rouge">Parse[String]</code>型の要素に変換される。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object WIGParser extends RegexParsers with Logger {
// remove quotation symbols
protected def unquote(s: String): String = s.substring(1, s.length() - 1)
def paramName: Parser[String] = """[A-Za-z0-9:\-_\.]+""".r
def value: Parser[String] = """[^\"'\s]+""".r
</code></pre>
</div>
<p>ダブルクォート、シングルクォートを含んだ文字列のパターン。エスケープシーケンス、Unicode文字列も表現できるように配慮。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> def stringLiteral: Parser[String] = ("\"" + """([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})*""" + "\"").r ^^
{ unquote(_) }
def quote: Parser[String] = ("'" + """([^'\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})*""" + "'").r ^^
{ unquote(_) }
</code></pre>
</div>
<p><code class="highlighter-rouge">^^ { ... }</code> をパターンの後につなげると、出力結果をパターンマッチにより加工できる。マッチした結果を後の処理で扱いやすい形に変更する際に使う。</p>
<h3 id="パターンを組み合わせた構文解析-parsing">パターンを組み合わせた構文解析 (parsing)</h3>
<p><a href="http://leoclock.blogspot.jp/2009/01/blog-post_27.html">正規表現の記述力だけでは限界がある</a>ため、正規表現でマッチした要素を組み合わせてより複雑な構文を記述できる。</p>
<p><code class="highlighter-rouge">|</code> (or)、 <code class="highlighter-rouge">~</code> (パターンの連結), 、<code class="highlighter-rouge">rep</code>(パターンの繰り返し) 、<code class="highlighter-rouge">repsep</code>(パターンを区切り文字のパターンを挟んで繰り返し連結)などが使える。</p>
<ul>
<li><a href="http://www.scala-lang.org/api/current/index.html#scala.util.parsing.combinator.Parsers$Parser">使える記号の一覧</a></li>
<li><a href="http://www.scala-lang.org/api/current/index.html#scala.util.parsing.combinator.RegexParsers">繰り返し記号など</a></li>
</ul>
<h4 id="コード例">コード例:</h4>
<div class="highlighter-rouge"><pre class="highlight"><code> def paramValue: Parser[String] = stringLiteral | quote | value
def param: Parser[(String, String)] = paramName ~ "=" ~ paramValue ^^ {
case key ~ "=" ~ value => (key, value)
}
def header: Parser[(String, Map[String, String])] = paramName ~ rep(param) ^^ {
case p ~ params => (p, Map() ++ params)
}
</code></pre>
</div>
<h3 id="ヘッダの解析">ヘッダの解析</h3>
<p>RegexParserの<code class="highlighter-rouge">parseAll</code>を呼び出すとパターンに文字列をマッチさせる。成功すると<code class="highlighter-rouge">Success(マッチした結果、残りのテキスト)</code>が返り、失敗すると <code class="highlighter-rouge">NoSuccess</code>が返る。</p>
<p>ここで<a href="http://www.scala-lang.org/api/current/index.html#scala.Either">Either</a> を使い、構文解析に失敗したときの処理(Left)と、成功した時の処理(Right)を同時に扱えるようにするのがコードを複雑にしないコツ。</p>
<p>以下はWIGのheader行(track, fixedStep, variableStep)を解析を開始するコード。Eitherを返す。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> def parseHeader(line: String) : Either[NoSuccess, (String, Map[String, String])] = {
parseAll(header, line) match {
case Success(result, next) => Right(result)
case failure : NoSuccess => Left(failure)
}
}
</code></pre>
</div>
<h3 id="行単位で処理を分ける">行単位で処理を分ける</h3>
<p><code class="highlighter-rouge">RegexParsers</code>では構文定義を短く書けるが、awkやANTLRのようにオートマトンを生成するわけではなく、正規表現によるマッチを繰り返すので残念ながら速度が速くない。プログラミング言語の解析程度なら問題ないが、ゲノム情報処理のように大規模データ全体を構文解析するには速度的に厳しい。行ごとに処理が分けられる文法なら、RegexParsersによる処理は必要な行に対してのみ行うと良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def parseLine(line: String): WIG = {
// 文字列の変換中に例外が発生したらLeft(例外)、成功すればRight(値)を返す
def convert[A](s:String, f:String => A) : Either[Throwable, A] =
scala.util.control.Exception.allCatch.either(f(s))
def toInt(s:String) = convert(s, {_.toInt})
def toFloat(s:String) = convert(s, {_.toFloat})
def invalidLine = WIG.Error("invalid line: " + line)
def parse : Either[NoSuccess, WIG] = {
if (line.startsWith("#"))
Right(WIG.Comment(line))
else if (line.startsWith("browser"))
Right(WIG.Browser(line))
else if (line.startsWith("track"))
parseHeader(line).right.map(header => WIG.Track(header._2))
else if (line.startsWith("variableStep")) {
parseHeader(line).right.map{
case (name, props) =>
(props.get("chrom"), toInt(props.getOrElse("span", "1"))) match {
case (Some(chr), Right(sp)) => WIG.VariableStep(chrom=chr, span=sp)
case _ => invalidLine
}
}
}
else if (line.startsWith("fixedStep")) {
parseHeader(line).right.map{
case (name, props) =>
val chrom = props.get("chrom")
val start = props.get("start")
val step = toInt(props.get("step").getOrElse("1"))
val span = toInt(props.get("span").getOrElse("1"))
(chrom, start, step, span) match {
case (Some(chr), Some(s), Right(st), Right(sp)) =>
WIG.FixedStep(chrom=chr, start=s.toInt, step=st, span=sp)
case _ => invalidLine
}
}
}
else {
// data line
val c = line.trim.split("""\s+""")
val r = c match {
case Array(step, value) => (toInt(step), toFloat(value)) match {
case (Right(st), Right(v)) => WIG.VariableStepValue(st, v)
case _ => invalidLine
}
case Array(value) => toFloat(value) match {
case Right(v) => WIG.FixedStepValue(value.toFloat)
case _ => invalidLine
}
case _ => invalidLine
}
Right(r)
}
}
parse match {
case Right(m) => m
case Left(error) => WIG.Error(error.toString)
}
}
</code></pre>
</div>
<h3 id="eitherを用いてエラー処理による分岐を減らしたコードにする">Eitherを用いて、エラー処理による分岐を減らしたコードにする</h3>
<p><a href="http://www.scala-lang.org/api/current/index.html#scala.Either"><code class="highlighter-rouge">Either[A, B]</code></a> は、<code class="highlighter-rouge">A</code>または<code class="highlighter-rouge">B</code>を返す型である。</p>
<p>上記のように <code class="highlighter-rouge">Either[(エラー情報), (結果)]</code>を返すとき、成功した場合は引き続きの処理を行いたいが、エラーの場合はそのまま次のコードにエラーを伝えたい場合がある。 <code class="highlighter-rouge">Either.right</code>を呼び出すと、値の内容が<code class="highlighter-rouge">Right</code>の型の場合は次の処理を行い、<code class="highlighter-rouge">Left</code>の型の場合は以降の処理を無視して<code class="highlighter-rouge">Left</code>の内容(この場合はエラー情報を)そのまま返すことができる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> // parseHeader(line) : Either[NoSuccess, (String, Map[String, String])] を返す
if (line.startsWith("track"))
parseHeader(line).right.map(header => WIG.Track(header._2)) // Either[NoSuccess, WIG] を返す
</code></pre>
</div>
<p>Eitherを使うことで、エラーを含んだデータであっても処理の流れを妨げないようにできる。</p>
文字列のformat
2012-07-05T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/05/string-format
<p>文字列を整形して出力したい。</p>
<p><strong>Scala2.10より、<a href="http://xerial.org/scala-cookbook/recipes/2013/01/30/string-interpolation">String interpolation</a>が使えるようになりtype safeな文字列の整形ができるようになりました。こちらがおすすめ (2013年1月)</strong></p>
<p>##
String.formatを使う。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>"Hello %s!".format("World!") // Hello World!
"Elapsed time: %.2f".format(43.5345) // 43.54
"Read %,d entries".format(100000000000L) // Read 100,000,000,000 entries
try {
...
}
catch {
case e:Exception =>
System.err.println("[%s] Error: %s".format(this.getClass.getName, e.getMesssages))
}
</code></pre>
</div>
<p>デバッグ用の文字列を出力するのに重宝。type safeでない(<code class="highlighter-rouge">%f</code>に文字列の値を渡してしまうと、<code class="highlighter-rouge">IllegalFormatException</code>が発生してしまう)のだが、他によい代替品が現れるまでは使う機会も多いだろう。</p>
<h2 id="formatによく使うシンボル">formatによく使うシンボル</h2>
<table>
<thead>
<tr>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="highlighter-rouge">%s</code></td>
<td>文字列</td>
</tr>
<tr>
<td><code class="highlighter-rouge">%d</code></td>
<td>整数</td>
</tr>
<tr>
<td><code class="highlighter-rouge">%f</code></td>
<td>浮動小数点数</td>
</tr>
<tr>
<td><code class="highlighter-rouge">%e</code></td>
<td>科学計算用の指数を含んだ数字。e-10などが付く</td>
</tr>
</tbody>
</table>
<h3 id="flagの例">flagの例</h3>
<p>%とこれらのシンボルの間にflag(s)を挟むことができる。</p>
<table>
<thead>
<tr>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="highlighter-rouge">,</code></td>
<td>3桁ごとにcommaを挟んで表示</td>
</tr>
<tr>
<td><code class="highlighter-rouge">(数字)</code></td>
<td>数字で指定された分のスペースを使って表示</td>
</tr>
<tr>
<td><code class="highlighter-rouge">.2</code></td>
<td>小数点以下二桁を表示</td>
</tr>
</tbody>
</table>
<h2 id="関連">関連</h2>
<p> * <a href="http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html">java.util.Formatter</a> より詳細な仕様はこちら</p>
長い文字列を作成する
2012-07-05T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/05/string-builder
<p>長い文字列を作成する。</p>
<h2 id="方法">方法</h2>
<p>短い文字列の場合。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val s = "Hello" + " World!!"
</code></pre>
</div>
<p>文字列をたくさん連結していく場合は、<a href="http://www.scala-lang.org/api/current/index.html#scala.collection.mutable.StringBuilder">StringBuilder</a>を使用する。</p>
<p><span class="label success">Good</span></p>
<div class="highlighter-rouge"><pre class="highlight"><code>val b = new StringBuilder
for(i <- 0 until 10) {
if(i > 0)
b.append(", ")
b.append(i)
}
val s = b.result // s = "0, 1, 2, 3, 4, 5, 6, 7, 8, 9"
</code></pre>
</div>
<p><span class="label important">Bad</span></p>
<div class="highlighter-rouge"><pre class="highlight"><code>var s = ""
for(i <- 0 until 10) {
if(i > 0)
s += ", " // 文字列のコピーを作成
s += i // 文字列のコピーを作成
} // s = "0, 1, 2, 3, 4, 5, 6, 7, 8, 9"
</code></pre>
</div>
<p>+=でStringに対して文字列を連結していくと、文字列のコピーが大量に発生してしまい性能が悪くなる。数個の文字列を連結するくらいなら<code class="highlighter-rouge">+=</code>でも問題ないが、何十以上の文字列を連結するのには不向き。</p>
正規表現で文字列の検索
2012-07-05T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/05/regex
<p>文字列中から正規表現にマッチした箇所を取り出したい。</p>
<h2 id="解法">解法</h2>
<p><a href="http://www.scala-lang.org/api/current/index.html#scala.util.matching.Regex">Regex</a>を使う。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val s = "GGACGATATAATTTATAATACCGT"
val r = "TATAA".r // Stringは.rで正規表現に変換できる
for(m <- r.findAllIn(s).matchData)
println("Found a match in [%s, %s)".format(m.start, m.end))
</code></pre>
</div>
<p><strong>実行結果</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>Found a match in [6, 11)
Found a match in [13, 18)
</code></pre>
</div>
<p>findAllInではマッチした文字列を切り出す<code class="highlighter-rouge">MatchIterator</code>(<code class="highlighter-rouge">Iterator[String]</code>を継承)が返るが、<code class="highlighter-rouge">matchData</code>を呼び出すことで、<code class="highlighter-rouge">Iterator[Match]</code>に変換でき、こちらでは、マッチの位置(start, end)や、マッチした文字列(matched)などの情報も得られる。</p>
<h3 id="マッチ箇所をグループに分ける">マッチ箇所をグループに分ける</h3>
<p>括弧によるグループを使用して、マッチした箇所を各々取り出せる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val r = "(chr)([0-9]+)".r
val l = List("chr1", "chr10", "chr21")
for(chr <- l; m <- r.findFirstMatchIn(chr)) {
val chrPrefix = m.group(1)
val chrNum = m.group(2)
println("prefix:%s, num:%s".format(chrPrefix, chrNum))
}
</code></pre>
</div>
<p>グループ番号0はパターン全体に対応。</p>
<p><strong>実行結果</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>prefix:chr, num:1
prefix:chr, num:10
prefix:chr, num:21
</code></pre>
</div>
<h3 id="グループに名前を付ける">グループに名前を付ける</h3>
<p>さらに、グループに名前を付けることもできる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val r = new scala.util.matching.Regex("(chr)([0-9]+)", "prefix", "num")
val l = List("chr1", "chr10", "chr21")
for(chr <- l; m <- r.findFirstMatchIn(chr)) {
println("prefix:%s, num:%s".format(m.group("prefix"), m.group("num")))
}
</code></pre>
</div>
<p><strong>実行結果</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>prefix:chr, num:1
prefix:chr, num:10
prefix:chr, num:21
</code></pre>
</div>
オブジェクトを比較する
2012-07-05T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/05/equality
<p>データ構造を<a href="http://xerial.org/scala-cookbook/recipes/2012/07/05/map">Map</a>などに格納する場合、<code class="highlighter-rouge">hashCode</code>と<code class="highlighter-rouge">equals</code>を適切に定義しないと、keyによる検索が上手くいかない。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object Point {
def apply(x:Int, y:Int) = new Point(x, y)
}
class Point(val x:Int, val y:Int) {
// Add and multiply by prime numbers
override def hashCode = (x + 31) * 31 + y
override def equals(other:Any) = other match {
case that: Point =>
(that canEqual this) && (this.x == that.x) && (this.y == that.y)
case _ => false
}
// Pointを継承した他のクラスのインスタンスでないかチェック
def canEqual(other:Any) = other.isInstanceOf[Point]
}
</code></pre>
</div>
<p>以上のようにhashCode, equalsの定義をするとMapに格納されたkeyを検索できるようになる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val m = Map(Point(1, 3) -> "A", Point(5, 5) -> "B")
val v = m(Point(1,3)) // "A" が見つかる
</code></pre>
</div>
<h2 id="継承されたクラスとの比較">継承されたクラスとの比較</h2>
<p>また、<code class="highlighter-rouge">canEqual</code>の部分でのチェックは、例えば以下のようにPointを拡張したPointWithColorを作成した場合、PointクラスのインスタンスとPointWithColorのインスタンスを誤って同一視しないために必要。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class PointWithColor(x:Int, y:Int, val color:String) extends Point(x, y)
</code></pre>
</div>
<p>もし上のコードから<code class="highlighter-rouge">canEqual</code>のチェック部分を取り除くと、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val p = new Point(1, 1)
val c = new PointWithColor(1, 1, "red")
p == c // trueになってしまう!!
</code></pre>
</div>
<h2 id="参照referenceとして比較">参照(reference)として比較</h2>
<p><code class="highlighter-rouge">==</code>では、equalsのメソッドを用いてオブジェクトの比較がなされるが、<code class="highlighter-rouge">eq</code>は参照としての比較がなされる。参照先が同じインスタンスを指す場合、<code class="highlighter-rouge">eq</code>による比較はtrueを返す。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> val p1 = new Point(1, 1)
p1: Point = Point@6bb
scala> val p2 = new Point(1, 1)
p2: Point = Point@6bb
scala> p1 == p2
res37: Boolean = true
scala> p1 eq p2
res38: Boolean = false
scala> val p3 = p1
p3: Point = Point@6bb
scala> p3 eq p1
res39: Boolean = true
</code></pre>
</div>
<h2 id="関連文献">関連文献</h2>
<p>より良いhash関数の計算に関しては<a href="http://en.wikipedia.org/wiki/Universal_hashing">Universal hashing</a>を参照のこと。</p>
<ul>
<li><a href="http://www.amazon.co.jp/Randomized-Algorithms-Cambridge-International-Computation/dp/0521474655">Randomized Altorithms</a> Section 8.4.1 (Universal Hash Families)</li>
</ul>
コンストラクタを複数定義する
2012-07-05T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/05/alternative-constructor
<p>クラスには、デフォルトのもの以外に、複数のコンストラクタを定義できる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class Interval(val start:Int, val end:Int) {
// 代替コンストラクタの定義
def this(point:Int) = this(point, point)
}
</code></pre>
</div>
<p>代替コンストラクタ(alternative consturctor)内では、必ずデフォルトコンストラクタを呼び出さなくてはならない。この制約はクラスの初期化の間違いなどのバグを減らすのに効く。</p>
<p><strong>使用例</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>val v = new Interval(1, 3) // デフォルトコンストラクタ
val p = new Interval(1) // 代替コンストラクタ new Interval(1, 1)が生成される
</code></pre>
</div>
<h2 id="コンストラクタの代わりにfactory-methodを使う">コンストラクタの代わりにfactory methodを使う</h2>
<p>コンストラクタにはクラス名以外の名前が付いていないので、コードの意味を十分に語れない。そこで、object内に新しいクラスを生成するfactory methodを提供すると良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object Interval {
// Interval(start, end)で新しいインスタンスを生成できるようにする
def apply(start:Int, end:Int) = new Interval(start, end)
// Interval.point(start, end)で、点を表す区間を生成するfactory method
def point(start:Int) = new Interval(point, point)
}
</code></pre>
</div>
<p><strong>使用例</strong></p>
<div class="highlighter-rouge"><pre class="highlight"><code>val v = Interval(1, 3)
val p = Interval.point(1)
</code></pre>
</div>
<p>factoryを作ることで、どのようなインスタンスを生成しているのかというコードの意図が伝えやすくなる。</p>
Mapを極める
2012-07-05T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/05/map
<p><a href="http://www.scala-lang.org/api/current/index.html#scala.collection.Map">Map</a>は key -> valueの索引のためのデータ構造。keyの値には重複を許さない。内部的にはHashMapが使われており、要素を挿入した順番は保持されない。</p>
<h2 id="mapの作成">Mapの作成</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> val m = Map(1 -> "Apple", 2 -> "Banana", 3 -> "Chocolate")
m: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> Apple, 2 -> Banana, 3 -> Chocolate)
</code></pre>
</div>
<p><code class="highlighter-rouge">1 -> "Apple"</code>の部分では、<code class="highlighter-rouge">(1, "Apple")</code>のTupleが生成され、最終的に<code class="highlighter-rouge">Map.apply(elems:(A, B)*)</code>が呼ばれている。</p>
<h3 id="builderを使ってmapを作成">Builderを使ってMapを作成</h3>
<p>ファイルやDBなどから大量のデータを読み込んで、immutableなMapを作りたい場合はBuilderを使うと良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val m = {
val b = Map.newBuilder[Int, String]
b += 1 -> "Apple"
b += ...
...
b.result
}
</code></pre>
</div>
<p>mutableなデータ(builder)は外に見せないように閉じ込めている。</p>
<h2 id="mapの使い方">Mapの使い方</h2>
<h3 id="keyの集合を取得">keyの集合を取得</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m.keys
res0: Iterable[Int] = Set(1, 2, 3)
</code></pre>
</div>
<h3 id="valueの集合を取得">valueの集合を取得</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m.values
res1: Iterable[java.lang.String] = MapLike(Apple, Banana, Chocolate)
</code></pre>
</div>
<h3 id="key-valueのエントリを取得">key, valueのエントリを取得</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> for((key, value) <- m) println("key:%s, value:%s".format(key, value))
key:1, value:Apple
key:2, value:Banana
key:3, value:Chocolate
</code></pre>
</div>
<h3 id="keyに対応する値の取得">keyに対応する値の取得</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m(1)
res4: java.lang.String = Apple
scala> m(4)
java.util.NoSuchElementException: key not found: 4
</code></pre>
</div>
<h3 id="optionを使ってvalueを取得">Optionを使ってvalueを取得</h3>
<p>例外処理のコードを書くのは面倒なので、Optionを返すこともできる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m.get(1)
res15: Option[java.lang.String] = Some(Apple)
scala> m.get(5)
res16: Option[java.lang.String] = None
</code></pre>
</div>
<p>Optionを使う利点は、keyに対応するentryがあってもなくてもコードの流れをさまたげないようにプログラミングできること。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> def printIfExists(key:Int) = for(v <- m.get(key)) println(v)
printIfExist: (key: Int)Unit
scala> printIfExists(1)
Apple
scala> printIfExists(5)
// 何も表示されない(println(v)が実行されない)
</code></pre>
</div>
<p>この動作は、None.foreach では何もしないように定義されていることによる。</p>
<h3 id="エントリが見つからないときのデフォルト値を与える">エントリが見つからないときのデフォルト値を与える</h3>
<p><code class="highlighter-rouge">getOrElse</code>を使う。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m.getOrElse(10, "N/A")
res21: java.lang.String = N/A
</code></pre>
</div>
<h2 id="変更可能mutableなマップを使う">変更可能(mutable)なマップを使う</h2>
<p>上記の例でmapに新しいエントリを追加すると、新しいMapが生成される。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> val m2 = m + (4 -> "Donut")
m2: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> Apple, 2 -> Banana, 3 -> Chocolate, 4 -> Donut)
</code></pre>
</div>
<p>元のマップには変更が加えられていない(persistent)</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m
res29: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> Apple, 2 -> Banana, 3 -> Chocolate)
</code></pre>
</div>
<p>Mapの内容をin placeで上書きしたい場合は、<code class="highlighter-rouge">scala.collection.mutable.Map</code>を使う。</p>
<h3 id="mutablemapの作成">mutable.Mapの作成</h3>
<p><code class="highlighter-rouge">+=</code>で追加、<code class="highlighter-rouge">-=</code>で削除。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> val m = scala.collection.mutable.Map[Int, String]()
m: scala.collection.mutable.Map[Int,String] = Map()
scala> m += 1 -> "Apple"
res22: m.type = Map(1 -> Apple)
scala> m += 2 -> "Banana"
res23: m.type = Map(1 -> Apple, 2 -> Banana)
scala> m += 3 -> "Cookie"
res24: m.type = Map(3 -> Cookie, 1 -> Apple, 2 -> Banana)
scala> m += 4 -> "Donut"
res25: m.type = Map(3 -> Cookie, 4 -> Donut, 1 -> Apple, 2 -> Banana)
scala> m -= 2
res26: m.type = Map(3 -> Cookie, 4 -> Donut, 1 -> Apple)
</code></pre>
</div>
<h3 id="mutablemapでエントリが存在しなければ更新を行う">mutable.Mapでエントリが存在しなければ更新を行う</h3>
<p><code class="highlighter-rouge">getOrElseUpdate(key, default)</code>を使う。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m.getOrElseUpdate(10, "Penut")
res27: String = Penut
</code></pre>
</div>
<p><code class="highlighter-rouge">10 -> Penut</code>が追加されている</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> m
res28: scala.collection.mutable.Map[Int,String] =
Map(10 -> Penut, 3 -> Cookie, 4 -> Donut, 1 -> Apple)
</code></pre>
</div>
<p><strong>応用例</strong></p>
<p><code class="highlighter-rouge">getOrElseUpdate</code>はエントリが存在しない場合の処理を一行に納めることができるので重宝する。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def getValue(key:Int) : String = {
def createNewEntry : String = {
// (初期化に必要な処理をする。例:DBへのクエリなど)
database.query(key)
}
// Mapにエントリが存在すればそれを返し、なければ初期化して追加し、追加した値を返す
m.getOrElseUpdate(key, createNewEntry)
}
</code></pre>
</div>
<h2 id="キャッシュとしてマップを使う">キャッシュとしてマップを使う</h2>
<p>Mapにエントリを格納するとMapから各エントリへの参照が保存される。しかし、Map内のエントリが不要になったとしても、Mapのインスタンスがある限りgarvage collector(GC)が参照関係を考慮してエントリを含むメモリ領域を回収してくれない。</p>
<p>そこで<a href="http://www.scala-lang.org/api/current/index.html#scala.collection.generic.GenMapFactory">WeakHashMap</a>を使うと、keyの値はWeakReference(GCが参照先として辿らない特別な参照)として管理されるため、エントリをGC(garvage collection)による回収の対象にしてくれる。</p>
<p>例えば初期化に時間がかかったり、メモリを大量に使うようなオブジェクトの一時的なキャッシュとしてWeakHashMapを使う。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class HeavyObject(id:Int) {
... (do some heavy initializations here)
}
object HeavyObject {
private val w = scala.collection.mutable.WeakHashMap[Int, HeavyObject]()
def apply(key:Int) =
w.getOrElseUpdate(key, new HeavyObject(key)) // new HeavyObjectは遅延評価される
}
{
val h = HeavyObject(1)
...
val ref = HeavyObject(1) // ここでは高い確率でWeakHashMap内の同じインスタンスが使い回される
}
// 1 -> HeavyObject(1) のエントリはGCの回収の対象
// いつ解放されるかはGCのタイミング次第(メモリが不足したときなど)
</code></pre>
</div>
<h2 id="関連">関連</h2>
<ul>
<li><a href="http://xerial.org/scala-cookbook/recipes/2012/07/05/equality">オブジェクトを比較する</a> 自分で定義したデータ構造をMapのkeyとして使うときにはhashCodeとequalsのmethodを定義し、keyの値による検索ができるようにする必要がある。</li>
</ul>
ScalaをMac OS Xにインストールする
2012-07-03T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/03/install-scala-in-mac-os-x
<p>Mac OS Xユーザーの場合、<a href="http://mxcl.github.com/homebrew/">Homebrew</a> をインストールしておくと、高速にScalaの開発環境を整えることができる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ brew install scala
$ brew install sbt
</code></pre>
</div>
<p>また、git、mercurialなども手軽にインストールできる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ brew install git
$ brew install mercurial
</code></pre>
</div>
<p>ちなみにGNU MakeなどのコマンドラインツールはApp StoreでXCodeをインストール後、<code class="highlighter-rouge">Preferences</code>-><code class="highlighter-rouge">Downloads</code>-><code class="highlighter-rouge">Command Line Tools</code> を選択してインストールする。</p>
REPLの使い方
2012-07-03T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/03/repl
<p>Scalaには<strong>REPL</strong> (Read-Eval-Print-Loop)と呼ばれる対話式実行環境がある。コードの動作を確認する場合にはREPLを使うと良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ scala
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_33).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val l = List("A", "B", "C", "D")
l: List[java.lang.String] = List(A, B, C, D)
scala> l.reverse
res0: List[java.lang.String] = List(D, C, B, A)
# 演算結果は自動的に変数に代入される
scala> res0
res1: List[java.lang.String] = List(D, C, B, A)
scala>
</code></pre>
</div>
<p>sbtを使った開発で、依存関係にあるライブラリをクラスパスに含めてREPLを動かしたい場合は、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ sbt console
[info] Loading project definition from /Users/leo/work/git/scala-cookbook/project
[info] Set current project to sample-project (in build file:/Users/leo/work/git/scala-cookbook/)
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_33).
Type in expressions to have them evaluated.
Type :help for more information.
scala>
</code></pre>
</div>
<p>とする。</p>
<p>REPL終了するには<code class="highlighter-rouge">:quit</code>と入力する。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> :quit
</code></pre>
</div>
順列、組み合わせ、冪集合を生成する
2012-07-03T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/03/permutations
<p>Scalaでは集合を並び替えた順列(permutation)や、組み合わせ(combination, 重複を含まない)、冪集合(power set)などを手軽に生成できる。</p>
<h2 id="順列の生成">順列の生成</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> val l = List("A", "B", "C", "D")
l: List[java.lang.String] = List(A, B, C, D)
scala> l.permutations
res0: Iterator[List[java.lang.String]] = non-empty iterator
scala> res0.map(_.mkString(",")).mkString("\n")
res1: String =
A,B,C,D
A,B,D,C
A,C,B,D
A,C,D,B
A,D,B,C
A,D,C,B
B,A,C,D
B,A,D,C
B,C,A,D
B,C,D,A
B,D,A,C
B,D,C,A
C,A,B,D
C,A,D,B
C,B,A,D
C,B,D,A
C,D,A,B
C,D,B,A
D,A,B,C
D,A,C,B
D,B,A,C
D,B,C,A
D,C,A,B
D,C,B,A
</code></pre>
</div>
<h2 id="組み合わせの生成">組み合わせの生成</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> l.combinations(3)
res2: Iterator[List[java.lang.String]] = non-empty iterator
scala> res2.map(_.mkString(",")).mkString("\n")
res3: String =
A,B,C
A,B,D
A,C,D
B,C,D
</code></pre>
</div>
<h2 id="冪集合の生成">冪集合の生成</h2>
<p>冪集合(power set)を生成する関数はないが、冪集合を生成する関数は以下のように簡単に書ける。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> def powerSet[A](s:TraversableOnce[A]) =
| s.foldLeft(Set(Set.empty[A])) {
| (set, element) => set union (set map (_ + element))
| }
powerSet: [A](s: TraversableOnce[A])scala.collection.immutable.Set[scala.collection.immutable.Set[A]]
scala> powerSet(l.toSet)
res5: scala.collection.immutable.Set[scala.collection.immutable.Set[java.lang.String]] = Set(Set(A, D), Set(), Set(A, B), Set(B, C), Set(B), Set(A, B, C), Set(C), Set(A, B, C, D), Set(C, D), Set(A, C), Set(B, C, D), Set(A, C, D), Set(B, D), Set(A), Set(D), Set(A, B, D))
</code></pre>
</div>
<p>生成の様子を表示すると以下のようになる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>step 1. Set(Set())
step 2. Set(Set(), Set(A))
step 3. Set(Set(), Set(A), Set(B), Set(A, B))
step 4. Set(Set(), Set(A, B), Set(B, C), Set(B), Set(A, B, C), Set(C), Set(A, C), Set(A))
step 5. Set(Set(A, D), Set(), Set(A, B), Set(B, C), Set(B), Set(A, B, C), Set(C), Set(A, B, C, D), Set(C, D), Set(A, C), Set(B, C, D), Set(A, C, D), Set(B, D), Set(A), Set(D), Set(A, B, D))
</code></pre>
</div>
<ul>
<li>参考:<a href="http://thinkmeta.wordpress.com/2010/06/28/scala-expressiveness/">Scala Expressiveness</a></li>
</ul>
Union Find
2012-07-03T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/03/union-find
<h2 id="問題">問題</h2>
<p>遺伝子のデータにはゲノム座標中で交差しているアノテーションが含まれている(splicing variant, 転写開始位置の違いなどによる)。
遺伝子情報に基づく解析を行う際、重複を避けるためこのような遺伝子はひとまとまりにして考えたい。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>|----(g1)-------| |---(g4)----| |----(g6)-----|
|-----(g2)----------| |---(g5)---|
|--(g3)----|
</code></pre>
</div>
<p>上記の遺伝子g1, g2, … , g6が与えられたとき、交差、あるいは包含関係にある遺伝子は同じ集合に入るようにする。</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">g1,</span><span class="w"> </span><span class="err">g2,</span><span class="w"> </span><span class="err">g3</span><span class="p">}</span><span class="err">,</span><span class="w"> </span><span class="p">{</span><span class="err">g4</span><span class="p">}</span><span class="err">,</span><span class="w"> </span><span class="p">{</span><span class="err">g5,</span><span class="w"> </span><span class="err">g6</span><span class="p">}</span><span class="w">
</span></code></pre>
</div>
<p>g1, g3は直接交差はしていないが、各々g2と交差しているので同じ集合に属している。</p>
<h2 id="考え方">考え方</h2>
<p>区間の交差判定については、<a href="http://xerial.org/scala-cookbook/recipes/2012/07/03/interval-sweep">こちら</a>を参考に。
区間を並べ替え、左端からsweepしながら交差しているものを列挙すれば良い。</p>
<h3 id="グループの作成">グループの作成</h3>
<p>n個の要素をグループに分類する問題として考える。</p>
<ul>
<li>find(e): 要素eがどのグループに属するかを見つける(グループの代表元を返す)</li>
<li>union(e1, e1): 要素e1と要素e2が含まれるグループを結合する</li>
</ul>
<h2 id="union-find">Union-Find</h2>
<p>互いに疎な集合を手軽に構築するデータ構造として、<a href="http://en.wikipedia.org/wiki/Disjoint-set_data_structure">Union-Find</a>が使える。Union-Findは集合を木で表し、union, findの2つの操作を持つデータ構造。</p>
<h3 id="参考文献">参考文献</h3>
<ul>
<li>Introduction to Algorithms 2nd Edition. Chapter21: Data Structures for Disjoint Sets</li>
</ul>
<h3 id="コード例">コード例</h3>
<p><a href="https://github.com/xerial/silk/blob/4f06b307c0a873b529446cc3ca6b1fa261f985d0/src/main/scala/xerial/silk/util/UnionFindSet.scala">UnionFindSet.scala</a>より抜粋</p>
<p>ノードを順次<code class="highlighter-rouge">+=</code>で追加できるように設計。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class UnionFindSet[E] {
/**
* Holder of the element with its rank and the parent node
*/
private class Container(val elem: E, var parent: E, var rank: Int) {
def isRoot : Boolean = elem == parent
}
/**
* Hold a map from elements to their containers
*/
private val elemToContainerIndex = collection.mutable.Map[E, Container]()
/**
* Retrieve the container of the element e
*/
private def containerOf(e: E): Container = {
def newContainer = new Container(e, e, 0) // Set the parent to this element
// If no container for e is found, create a new one
elemToContainerIndex.getOrElseUpdate(e, newContainer)
}
/**
* Add a new element
* @param e
*/
def +=(e: E): this.type = {
containerOf(e) // create a new containerOf for e if it does not exist
this
}
</code></pre>
</div>
<p><code class="highlighter-rouge">find</code>でグループの代表元(root)を求める。同じ集合に属するノードは、ツリーで管理されているが、ルートまでのパス中のノードを同時にルートに直結させている(path compression).</p>
<div class="highlighter-rouge"><pre class="highlight"><code> /**
* Find the representative (root) element of the class to which e belongs
*/
def find(e: E) : E = {
val c = containerOf(e)
if(c.isRoot)
e
else {
// path compression: recursively connect all elements
// in the path from e to the root directly to the root
c.parent = find(c.parent)
c.parent
}
}
</code></pre>
</div>
<p>ここで再帰的に通ったノードの親をルートに張り替えるpath compressionが行われている。</p>
<p><code class="highlighter-rouge">union(x, y)</code>ではx, yの代表元を求めてそれを結合することで、2つの集合の結合を行う。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> /**
* Union the two sets containing x and y
*/
def union(x: E, y: E) {
val xRoot = containerOf(find(x))
val yRoot = containerOf(find(y))
// Compare the rank of two root nodes
if (xRoot.rank > yRoot.rank) {
// x has a higher rank
yRoot.parent = xRoot.elem
}
else {
// y has a higher rank
xRoot.parent = yRoot.elem
// If the ranks are the same, increase the rank of the other
if (xRoot.rank == yRoot.rank)
yRoot.rank += 1
}
}
</code></pre>
</div>
<p>二つの集合を結合するときは、必ずrankの大きい方の下にrankの小さな木を結合するようにする。</p>
<h3 id="union-findの計算量">Union-Findの計算量</h3>
<p>path compressionと、rankを基準にした木の組み方により、n回のunion, findにかかる計算時間は<em>O(n A(n))</em> A(n)は<a href="http://en.wikipedia.org/wiki/Ackermann_function">アッカーマン関数</a>の逆関数、になることが知られている。</p>
<h3 id="union-findをさらに使いやすくする">Union-Findをさらに使いやすくする</h3>
<p>Setを拡張し、iterator、要素数などを取得できるように。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class UnionFindSet[E] extends collection.mutable.Set[E] {
(中略)
private def containerList = elemToContainerIndex.values
override def size = elemToContainerIndex.size
def contains(e: E) = elemToContainerIndex.contains(e)
/**
* Iterator of the elements contained in this set
* @return
*/
def iterator = containerList.map(_.elem).toIterator
</code></pre>
</div>
<p>さらに、代表元のみを探索、あるノードと同じグループに属するノード集合、グループを探索するためのiteratorなどを定義。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>/**
* Iterator of the root nodes of the groups
*/
def representatives: Iterable[E] =
for(c <- containerList if c.isRoot) yield c.elem
/**
* Return the elements belonging to the same group with e
*/
def elementsInTheSameClass(e: E) : Iterable[E] = {
val root = containerOf(find(e))
for(c <- containerList if find(c.elem) == root.elem) yield c.elem
}
/**
* Iterator of each group
*/
def groups: Iterable[Iterable[E]] =
for((root, containers) <- containerList groupBy(_.elem)) yield
containers map (_.elem)
</code></pre>
</div>
<h2 id="関連">関連</h2>
<p>上記のUnion-Findの実装はimmutableな設計にはなっていない。これをimmutable (persistent)にする実装も提案されている。</p>
<ul>
<li>Sylvain Conchon and Jean-Christophe Filliatre. 2007. A persistent union-find data structure. In Proceedings of the 2007 workshop on Workshop on ML (ML ‘07). ACM, New York, NY, USA, 37-46. DOI=10.1145/1292535.1292541 <a href="http://doi.acm.org/10.1145/1292535.1292541">http://doi.acm.org/10.1145/1292535.1292541</a></li>
</ul>
交差している区間の列挙
2012-07-03T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/03/interval-sweep
<h2 id="問題">問題</h2>
<p>以下のリード(ゲノム配列の断片)で交差しているものを列挙せよ(pileup)。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>|----(r1)-------| |---(r4)----| |----(r6)-----|
|-----(r2)----------| |---(r5)---|
|--(r3)----|
</code></pre>
</div>
<p>上記のリードセットr1, r2, … , r6が与えられたとき、交差しているリードは以下の3組。</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="p">{</span><span class="err">r1,</span><span class="w"> </span><span class="err">r2</span><span class="p">}</span><span class="err">,</span><span class="w"> </span><span class="p">{</span><span class="err">r2,</span><span class="w"> </span><span class="err">r3</span><span class="p">}</span><span class="err">,</span><span class="w"> </span><span class="p">{</span><span class="err">r5,</span><span class="w"> </span><span class="err">r6</span><span class="p">}</span><span class="w">
</span></code></pre>
</div>
<p>この問題は、リードのcoverage計算, SNPコールのための前処理にも使われておりゲノム情報処理では頻出。</p>
<h2 id="考え方">考え方</h2>
<h3 id="区間の交差判定">区間の交差判定</h3>
<p>区間を表現するクラスを作成。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class Interval(val start:Int, val end:Int)
object Interval {
// Interval(s, e) でinstanceを作成できるようにするhelper method
def apply(start:Int, end:Int) = new Interval(start, end)
}
</code></pre>
</div>
<p>区間に順序を定義する。<a href="http://www.scala-lang.org/api/current/scala/math/Ordering.html">scala.math.Ordering</a> を使用。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object IntervalOrdering extends Ordering[Interval] {
def compare(x:Interval, y:Interval) : Int = {
// startの小さい順に並べる
val diff = x.start - y.start
if(diff == 0)
x.end - y.end // startが同じならendの小さい順に並べる
else
diff
}
}
</code></pre>
</div>
<p>区間を上の順序を使って並べ替える。</p>
<div class="highlighter-rouge"><pre class="highlight"><code> // 1 2 5 6 7 8 10 12 13 14 15 16
// |---------| |----| |-----|
// |-----------| |----| |-----|
// |---|
val in = List(Interval(1, 5), Interval(2, 7),
Interval(6,8), Interval(10, 12),
Interval(10, 12), Interval(13, 15),
Interval(14, 16))
val sorted = in.sorted(IntervalOrdering)
</code></pre>
</div>
<p>その後、左端(startの小さい順)からsweepする。
sweepする際にはstartだけでなく、endの情報もpriority queue(優先度付きキュー)に入れて管理する。</p>
<h2 id="コード例">コード例</h2>
<p>pullスタイル(データを引っ張りながら使う)で使えるようにIteratorを定義している。push型(生成した結果をどんどん第三者に書き出す形)にすればもう少し平易なコードになる。</p>
<p><a href="https://github.com/xerial/genome-weaver/blob/fba37256f6d372993989cc8e77bfab02a6700ae7/lens/src/main/scala/utgenome/weaver/lens/OverlapSweeper.scala">OverlapSweeper.scala</a></p>
<div class="highlighter-rouge"><pre class="highlight"><code>import collection.{mutable, SortedSet}
import annotation.tailrec
class OverlapSweeper[A <: Interval](list:TraversableOnce[A]) extends Iterator[Seq[A]] {
private val it = list.toIterator
private var nextOverlappedSet : Option[Seq[A]] = None
private var sweepLine = 0
// endの値の小さい順にqueueから取り出せるように順序を定義
private val endValueQueue = new mutable.PriorityQueue[A]()(new Ordering[A] {
def compare(x: A, y: A) = {
val diff = y.end - x.end // lower end value has high priority
if(diff == 0)
y.start - x.start
else
diff
}
})
def hasNext = {
@tailrec
def findNextOverlap : Option[Seq[A]] = {
if(it.hasNext) {
val r = it.next
endValueQueue += r // enqueue
sweepLine = r.start
// sweep intervals whose end value is less than sweepLine
while(!endValueQueue.isEmpty && endValueQueue.head.end < sweepLine) {
endValueQueue.dequeue
}
if(endValueQueue.size > 1)
Some(endValueQueue.clone.toSeq) // queueの中身はmutableなので敢えてコピーを作成
else
findNextOverlap
}
else
None
}
nextOverlappedSet = nextOverlappedSet.orElse(findNextOverlap)
nextOverlappedSet.isDefined
}
def next() = {
if(hasNext) {
val e = nextOverlappedSet.get
nextOverlappedSet = None
e
}
else
throw new NoSuchElementException("no more elements")
}
}
</code></pre>
</div>
<h2 id="動作をテストする">動作をテストする</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>val in = List(Interval(1, 5), Interval(2, 7), Interval(6,8),
Interval(10, 12), Interval(10, 12), Interval(13, 15), Interval(14, 16))
val sorted = in.sorted(IntervalOrdering)
val overlapped = new OverlapSweeper(sorted)
for(s <- overlapped) {
// overlapしていると報告された区間のすべての組み合わせをチェック(combination)
for(c <- s.combinations(2)) {
val a = c(0)
val b = c(1)
a.intersectWith(b) should be (true)
}
}
</code></pre>
</div>
<h2 id="拡張">拡張</h2>
<p><a href="https://github.com/xerial/genome-weaver/blob/fba37256f6d372993989cc8e77bfab02a6700ae7/lens/src/main/scala/utgenome/weaver/lens/GenomeRange.scala#L258">GInterval</a>
のように、染色体名、strandの情報が含まれる場合、上記のアルゴリズムのままでは上手くsweepできない。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class GInterval(val chr:String, val start:Int, val end:Int, val strand:Strand)
</code></pre>
</div>
<p>どう拡張すれば良いか?</p>
<h3 id="リードセットがメモリに収まりきる場合">リードセットがメモリに収まりきる場合</h3>
<p>染色体ごとにデータをグループ分けして、それぞれをsweep。簡単。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val l : List[GInterval] = ...
val groups = l.groupBy(_.chr)
// parllel collectionで染色体ごとに並列処理
for((chr, lst) <- groups.par; overlappedReadSet <- new OverlapSweeper(lst)) {
...
}
</code></pre>
</div>
<h3 id="リードセットがメモリに収まりきらない場合">リードセットがメモリに収まりきらない場合</h3>
<p>染色体名を覚えておき、異なる染色体のリードが入力されたら、queueにたまっているものをすべてsweepする。</p>
関数型言語の特徴
2012-07-02T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/02/functional-programming
<h2 id="コーディングのスタイル">コーディングのスタイル</h2>
<ul>
<li>コードを逐次実行しながら副作用(変数の内容の書き換え)を起こす<a href="http://en.wikipedia.org/wiki/Imperative_programming">命令型 (imperative programming)</a>のコードをなるべく排除する</li>
<li>副作用を避けるために <strong>immutable</strong>(変更不可能)なデータを中心に使う
<ul>
<li>値の変化は、関数に「immutableなデータを入力 -> 新しいデータを出力」という形で行う</li>
</ul>
</li>
<li>関数そのものも、関数の引数として渡す
<ul>
<li>関数がfirst-class citizenという言い方をよくする</li>
<li>C++、Javaでも関数に関数へのポインタ(リファレンス)などを渡せるが、関数が定義されたコンテキストの情報(変数の値など)までも含めて他の関数に渡すのは大変。</li>
</ul>
</li>
</ul>
<h2 id="q-副作用を避けるのは何故か"><strong>Q</strong>. 副作用を避けるのは何故か?</h2>
<p><strong>A</strong>. プログラミングを簡単にするため。</p>
<p>例えば、文字列型 String のデータが変更可能だったとする。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val key1 = "Apple"
val key2 = "Banana"
val set = SortedSet(key1, key2) // "Apple", "Banana"の順に並び替えを維持するデータ構造
// もしkey1の内容を以下の用に書き換えられるとしたら。。。
key1(0) = "Z" // key1は"Zpple"になる
// ここでSortedSetの中身はどうなっている? "Banana", "Zapple"の順番になっていてほしいが。。。
</code></pre>
</div>
<p>keyの値が外部で変化すると、SortedSetの中で保管しているkeyの並び順も更新する必要がある。
これに対処する方法として、</p>
<ol>
<li>SortedSetに格納されているデータの変更を探知して、並び順を更新する</li>
<li>SortedSetに格納する際に、データのコピーを作成して、コピーをSortedSetに格納する</li>
<li>SortedSetにアクセスするたびに並び替えを行う</li>
</ol>
<p>などが考えられる。</p>
<p>1番目の方法はひどく実装が大変になる。keyの値の変更を探知する<a href="http://en.wikipedia.org/wiki/Observer_pattern">Observer</a>をkey毎に用意し、Stringが更新されるたびに並び順を変更する。もし、マルチスレッドプログラミ
ングを行っている場合、SortedSetへのアクセスとSortedSetの内容の更新が衝突しないように排他制御を行う必要がある。2番目の方法は簡単だがデータのコピーのコストが重い。3番目の方法になるようでは、SortedSetのようにO(log n)でデータを検索できるデータ構造を使う意味を失う。</p>
<p>また、このようなコードをデバッグするのは困難を極める。
global変数(プログラムのどこからでも変更できる)を用いたコードが今日では衰退しているのは、
変数の内容の変化を起こすコードと、その変化のタイミングを管理するのが大変だったことによる。</p>
<h3 id="解決策">解決策</h3>
<p>Stringをimmutableにすればよい。</p>
<p>immutableにすることで、上記のようなことで悩む必要はなくなる。実際、
Scala/JavaのStringはimmutableになっている。また、SortedSet などの実装はimmutableなデータが格納されることを前提にしており、
性能のためにデータのコピーを避け、文字列へのリファレンスのみを格納している。
parallel/concurrent programmingにおいても、StringやSortedSetの内容がimmutableであることが保証されていると、ロックなどを取得する必要がなくコードの性能が良くなる。さらに、コードの実行の度に動作が違うなど、発見が困難かつ再現しにくいという深刻なタイプのバグに悩まされなくなる。</p>
<h2 id="immutableなデータを使い初期化忘れを防ぐ">immutableなデータを使い、初期化忘れを防ぐ</h2>
<p>Scalaではclassでデータ構造を作成する際も、パラメータはすべてimmutableにし、初期化を必ず行うように強制できる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class Book(val id:Int, val title:String, val publisher:String)
val b = new Book(1, "Programming in Scala", "Artima Press")
</code></pre>
</div>
<p>Javaではimmutableであることに注意しないと、以下のようなコードを書いてしまう。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// このような書き方は避けたい
class Book {
public int id;
public String title;
public String publisher;
}
Book b = new Book();
b.id = 1;
b.title = "Programming in Scala";
// publisherの情報を設定するのを忘れてしまった!!
System.out.println(b.publisher); // NullPointerExceptionが発生
</code></pre>
</div>
<p>Javaで安全にクラスの初期化を行えるようにするには以下のようにする。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class Book {
// finalを付けると、初期化時以外変更不能な変数になる
public final int id;
public final String title;
public final String publisher;
public Book(int id, String title, String publisher) {
this.id = id;
this.title = title;
this.publisher = publisher;
}
}
</code></pre>
</div>
<p>Scalaでは、immutableなデータを好んで使ってもらえるよう配慮されており、以下の一行で済む。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class Book(val id:Int, val title:String, val publisher:String)
</code></pre>
</div>
<p>より安全にするには、nullかどうかのチェックも入れると良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class Book(val id:Int, val title:String, val publisher:String) {
// クラスの初期化時に実行されるコード
if(title == null || publisher == null)
sys.error("null is passed as an argument")
}
</code></pre>
</div>
<h3 id="補足">補足</h3>
<p>JavaではBeans(データベースやJSONなどのデータをもとに、クラスを初期化する)などを使う場合、
止むを得ず上記のようにpublicなフィールドを使って、
安全でない書き方をすることがある。<a href="http://en.wikipedia.org/wiki/Builder_pattern">Builder pattern</a>を使うなど、
いくつか初期化の安全性を確保する方法があるが、楽な書き方とは言いがたい。</p>
Scalaの利点
2012-07-02T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/07/02/advantages-of-scala
<p>バイオインフォマティクスの分野では、現場で動くコードを書けるプログラミング言語でないと使えません。
Scalaが本当に現場で使えるかどうかわかるまで、実際にコードを書いてみたり、開発環境、ライブラリを調べるなど調査に費やした時間も膨大でした。
そのときの自分に教えてあげるつもりでScalaの利点をここにまとめていきます。</p>
<h2 id="関数型言語であるが関数型言語でない">関数型言語であるが、関数型言語でない</h2>
<p>Scalaでは関数型言語のスタイルに固執する必要がない。命令型、副作用のあるコードも書けるので、慣れるに従い関数型のスタイルに近づければ良い。
C++, Java、Perlなど命令型のコードが多い言語に慣れていると、最初のうちは関数型のコードをどう書けば良いかわからないことが多いと思うが、
<a href="http://www.scala-lang.org/api/current/index.html">Scala API</a>にあるライブラリの使い方に習熟してくると、これらをどう組み合わせてコードを書けばよいかが見えてくるようになる。</p>
<p><a href="http://lampwww.epfl.ch/~odersky/">Martin Odersky</a>のProgramming in Scalaの本にも、<em>well-trained eyes</em> (訓練された目では) という表現がよく出てくるが、
私自身も、Scalaを覚えたての頃と、Scalaに慣れた現在ではコードを見る目、書き方がずいぶんと変わった。</p>
<h2 id="簡潔にコードを書ける">簡潔にコードを書ける</h2>
<p>型推論や構文の工夫により、Rubyなど動的型付け言語と同じくらいコーディングがしやすくなっている。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// Mapの作成
val m = Map(1 -> "A", 2 -> "B", 3 -> "C")
for((key, value) <- m) {
...
}
</code></pre>
</div>
<p>これを敢えて冗長に書くと、、、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val m : Map[Int, String] =
Map.apply[Int, String](Seq[Tuple2[Int, String]]
(new Tuple2[Int, String](1, "A"), new Tuple2[Int, String](2, "B"), new Tuple2[Int, String](3, "C"))
// 型名をすべて補って書き下すと...
m.foreach[Tuple2[Int, String]]{ (entry:Tuple2[Int, String]) =>
entry match {
case (key:Int, value:String) => ...
}
}
</code></pre>
</div>
<p>となるが、このような詳細をコーディング時に気にする必要がない。(もちろん詳細を知っておくと、Scalaでコードライブラリを開発するときの力になる)</p>
<h2 id="開発環境ライブラリの充実">開発環境、ライブラリの充実</h2>
<p><a href="http://www.jetbrains.com/idea/">IntelliJ</a>, <a href="https://github.com/harrah/xsbt/">sbt</a>などが
コミュニティでよく使われており、大きなプロジェクトの開発にもScalaは実用的に使えるようになってきた。</p>
<p><a href="http://www.eclipse.org/">Eclipse</a>で<a href="http://scala-ide.org/">Scala IDE for Eclipse</a>を使っても一応開発できるが、2012年7月の時点では、
IntelliJ + Scalaプラグインの方が使い勝手(syntax highlight, type inferenceによる文法エラーの検知)が良い。</p>
<p>sbtで特筆すべき点は、コードの更新をモニターして、変更があればすぐ再コンパイルを行い、テストコードの実行までを自動で行ってくれる。
Scalaのコードはコンパイルに多少時間がかかるが、この機能により開発時のストレスが少ない。</p>
<p>Javaで一般的な<a href="http://maven.apache.org/">Maven</a>による開発スタイルを踏襲することもできるが、sbtを使う方が良い。
mavenにできてsbtにできないこともたくさんあるが、sbtにできてmavenにできないことを実装する方が大変に思う。
sbtの拡張はsbtのソースコードとにらめっこして、Scalaで書けばよい。作成したプラグインもGitHubに置くなどの手段が使える。一方mavenプラグインでは、XMLによる仕様の記述、クラスの階層関係の把握、maven centralにdeployするなど、一筋縄ではいかない箇所が多くある。</p>
<p>Javaのコードとの親和性に関しても、Scala 2.8でcollectionクラスの大幅な改善により、格段に使い勝手が良くなった。
Scala2.9では、並列処理のためのコレクションの拡張が行われており、マルチコアのための計算も簡単になっている。
実際、私自身も10CPU以上を使った演算などを日常的に行えるようになって助かっている。</p>
<h2 id="練られた言語設計">練られた言語設計</h2>
<p>ScalaはJavaと同様JVMの上で動く言語であるが、オブジェクト指向言語としてだけ見ても、Javaと比較して改善されている点が多々ある。</p>
<ul>
<li>implicit conversionによる機能の追加</li>
</ul>
<p>例えば、Stringにはformatというメソッドはないが、<a href="http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.StringOps">StringOps</a>などに自動的に変換して機能を追加できる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>"Hello %s!".format("World")
// Javaでは以下のように書かなければならなかった
String.format("Hello %s", "World")
</code></pre>
</div>
<ul>
<li>Java言語のリリース頻度は、使っているユーザー数が多いために慎重になっているためか、非常に遅い。新しいリリースを待つくらいならScalaでコードを書き始める方が良い</li>
<li>例えば以下のような機能が待望されているが、Javaで使えるようになるのがいつになることやら…
<ul>
<li>コードブロック (clojure, lambda function)</li>
<li>try catch with resources (Scalaなら<a href="http://xerial.org/scala-cookbook/recipes/2012/06/27/loan-pattern">loan pattern</a>を自分で実装すればよい)</li>
<li>traitによるmixin(多重継承の特殊なケース)の実現
<ul>
<li>コードの再利用、拡張がより広く可能になった</li>
<li>例えば、<a href="http://www.scala-lang.org/api/current/index.html#scala.collection.Iterator">Iterator</a>を継承してメソッドを2つ(hasNext, next)実装するだけで、foreach, map, foldなどcollectionクラスで使える便利なメソッドがすべて追加される。</li>
<li>linearlizationにより、C++などの多重継承で問題だった階層関係の順番の曖昧さを解決</li>
</ul>
</li>
</ul>
</li>
<li>Covariance, contravarianceの導入により、自然な型のマッピングが可能に</li>
</ul>
<p>Covarianceの例 (List[Banana], List[Apple]はList[Fruit]のsubtypeとして扱える)</p>
<div class="highlighter-rouge"><pre class="highlight"><code>trait Fruit
class Apple extends Fruit
class Banana extends Fruit
// ListはList[+A] (covariance)として定義されている
val l : List[Fruit] = List[Banana](new Banana, new Banana) ++ List[Apple](new Apple)
</code></pre>
</div>
<ul>
<li>関数に渡す関数の型なども、covariance, contravarianceのおかげで汎用的になり、コードの再利用性が高まっている. <code class="highlighter-rouge">Function2[-A, +B]</code>など。</li>
<li>Checked exceptionの廃止
<ul>
<li>Javaでは<code class="highlighter-rouge">method(..) throws xxException</code>という形でexceptionの型までメソッドに指定しなくてはならないために、汎用的なライブラリを書く障害になっていた。例えば同じようなコードを再利用できる場所でも、DBException, IOExceptionなど内部で発生する例外の型が違うために、APIでは親クラスのthrows Exceptionを使うように設計しなくてはならず、APIを使う側では何のエラーだかわからないExceptionをcatchするコードを大量に書く必要があった。Scalaでは、throws … と書かなくても良くなり、programのmain関数内など、必要最低限の位置で例外をcatchすれば良いようになっている。</li>
</ul>
</li>
<li>Pattern matchingの機能
<ul>
<li><a href="http://www.artima.com/scalazine/articles/pattern_matching.html">パターンマッチ</a>が実装されているおかげで、<a href="http://en.wikipedia.org/wiki/Visitor_pattern">Visitorパターン</a>をもう書かなくてもいいと思うだけでありがたい。</li>
</ul>
</li>
<li>Type erasureへの対応
<ul>
<li>Scalaのクラスファイルには、実は詳細な型情報を記したsignatureが埋め込まれており、JVMでtype erasureにより実行時に失われてしまうような型情報も、Scalaでは実行時に取り出すことができる(ただしScalaで書かれたクラスに限る)</li>
</ul>
</li>
</ul>
<h3 id="scalaの言語デザインについてためになる記事">Scalaの言語デザインについてためになる記事</h3>
<p>Scalaを作ったMartin Odersky氏への以下のインタビュー記事を読むと、なぜScalaの言語が今のようなデザインになっているのかがよくわかる。妥協もあり、積極的に関数型言語、オブジェクト指向言語の融合をはかった部分もあり。Javaの不便を乗り越えるとともに関数型言語の良い面を取り入れるため最大限の努力をしている様子が伺える。</p>
<ul>
<li><a href="http://www.artima.com/scalazine/articles/origins_of_scala.html">The Origins of Scala - A Conversation with Martin Odersky</a></li>
<li><a href="http://www.artima.com/scalazine/articles/goals_of_scala.html">The Goals of Scala’s Design - A Conversation with Martin Odersky</a></li>
<li><a href="http://www.artima.com/scalazine/articles/scalas_type_system.html">The Purpose of Scala’s Type System - A Conversation with Martin Odersky</a></li>
</ul>
Classを作成する
2012-06-30T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/30/class
<h2 id="クラスを使うタイミング">クラスを使うタイミング</h2>
<ul>
<li>多くのパラメータを同時に扱うとき</li>
<li>関数の引数が多くなったとき</li>
<li>実装の詳細を効率的に「忘れたい」とき
<ul>
<li>参考 <a href="http://mayah.jp/scratchleaf/2008/%E8%80%83%E3%81%88%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E6%B8%9B%E3%82%89%E3%81%9B%E3%82%8B%E6%A7%98%E3%81%AB%E6%9B%B8%E3%81%8F">「考えることを減らせる様に書く」</a></li>
</ul>
</li>
</ul>
<h2 id="クラスとは">クラスとは</h2>
<p>以下のように考えれば良い。</p>
<ul>
<li>データのまとまり。レコード</li>
<li>プログラムを実行するためのインターフェース (API)</li>
<li>計算に必要なデータをまとめるためのコンテクスト</li>
<li>機能のまとまり</li>
</ul>
<h2 id="classの定義">Classの定義</h2>
<p>例えば遺伝子のクラスは以下のように定義できる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// 遺伝子クラスの定義
class Gene(val name:String, val chr:String, val start:Int, val end:Int, val strand:Strand)
</code></pre>
</div>
<p>valをパラメータ名に付けると、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val g = new Gene("gene1", "chr1", 10000, 20000, Strand.Forward)
g.name
</code></pre>
</div>
<p>とクラスの外部からパラメータにアクセスできるようになる。何もつけないとクラスの内部でしかパラメータにアクセスできない。Javaではパラメータにアクセスするためのgetter/setterを用意する、あるいはパラメータに<code class="highlighter-rouge">public final</code>と付けるのが推奨されていたが、Scalaではパラメータにはvalを使って<a href="http://xerial.org/scala-cookbook/recipes/2012/07/02/functional-programming">immutableにして副作用を避ける</a>のが基本で、そうしたプログラミングが苦にならないよう配慮されている。</p>
<p>遺伝子を定義したらExon, Intronなども同じように定義できる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// Exon
class Exon(val chr:String, val start:Int, val end:Int, val strand:Strand)
</code></pre>
</div>
<p>遺伝子もexonもゲノム座標中の区間として考えると同類なので、共通部分をGIntevalとして抽出してみる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// genome中の区間[start, end)を表すクラス
class GInterval(val chr:String, val start:Int, val end:Int, val strand:Strand)
</code></pre>
</div>
<p>GIntevalクラスを継承するようにしてGene, Exonを書き換える。</p>
<ul>
<li>このような大きな変更の前には<code class="highlighter-rouge">git commit</code>しておくとよい。commit前に変更を始めてしまった場合は、<code class="highlighter-rouge">git stash</code> -> <code class="highlighter-rouge">git stash branch (new branch name)</code>のコンボ。</li>
</ul>
<p>Gene, ExonをGIntervalから継承させる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class Gene(name:String, chr:String, start:Int, end:Int, strand:Strand)
extends GInteval(chr, start, end, strand)
class Exon(chr:String, start:Int, end:Int, strand:Strand)
extends GInteval(chr, start, end, strand)
</code></pre>
</div>
<p>Gene, Exonのコンストラクタの引数からvalが消えている。こうすると、親クラスと同名のパラメータが二重定義されないように、Scalaのコンパイラが頑張ってくれる。(変数を上書きしたい場合は、<code class="highlighter-rouge">override</code>を付ける)</p>
<p>入力量はさほど減っていないが、これでGene, Exonに共通する操作はGIntevalで定義すればよくなった。たとえば、区間の交差を判定するメソッドをGIntervalに追加すると、Gene, Exonで共通に使えるようになる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class GInterval(val chr:String, val start:Int, val end:Int, val strand:Strand) {
def intersectWith(other:GInterval) = {
chr == other.chr && start < other.end && other.start <= end
}
}
</code></pre>
</div>
<p><a href="http://xerial.org/scala-cookbook/recipes/2012/07/03/interval-sweep">交差する区間をsweepする</a>例で定義したクラスも、GIntervalから派生したクラス全般に適用できる。</p>
ScalaのEnumerationは使うな
2012-06-29T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/29/enumeration
<h2 id="scalaのenumerationは使いにくい">ScalaのEnumerationは使いにくい</h2>
<p>Scalaには列挙型として<a href="http://www.scala-lang.org/api/current/index.html#scala.Enumeration">Enumeration</a>が用意されているが、以下の理由で使いにくい。</p>
<ul>
<li>値にメソッドを定義できない</li>
<li>DNAというEnumerationを定義しても、個々の値は、DNA.Value型として扱わなければならないため、コードが不自然になる。</li>
</ul>
<h3 id="enumerationを使ったコード例">Enumerationを使ったコード例</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>object DNA extends Enumeration {
val A, C, G, T, N = Value
}
val base : DNA.Value = DNA.A
</code></pre>
</div>
<p>ここでDNA.Value型を拡張することが許されていないので、ラベルとしての機能しか持たせることができない。</p>
<h2 id="解決策">解決策</h2>
<p>ScalaではJavaのコードが使えるので、Javaの<a href="http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html">enum</a>を使うのが簡便だが、Scalaのコードだけで同様の機能を実装するには、objectを使うと良い。</p>
<h2 id="コード例">コード例</h2>
<p>DNAの塩基を表すコード。<a href="https://github.com/xerial/genome-weaver/blob/develop/lens/src/main/scala/utgenome/weaver/lens/DNA.scala">genome-weaverのDNA.scala</a>より抜粋。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>object DNA {
// objectで定義するとsingletonになる
case object A extends DNA(0)
case object C extends DNA(1)
case object G extends DNA(2)
case object T extends DNA(3)
case object N extends DNA(4)
// DNAの文字列をすべて並べる。
val values = Array(A, C, G, T, N)
// 用途によって別の集合を定義することもできる
val exceptN = Array(A, C, G, T)
private val codeTable = Array(A, C, G, T, N, N, N, N)
def complement(code:Int) : DNA = codeTable((~code & 0x03) | (code & 0x04))
}
// sealedを付けると、DNAを拡張したクラスはこのファイル内でしか定義できない
// abstractを付けると、DNAを拡張したクラスはA, C, G, T, N以外にないことを保証できるので
// match文がexhaustive(すべてのケースを網羅)になる
sealed abstrat class DNA(val code:Int) {
// A, C, G, T, Nをcase objectとすると、クラス名を表示するtoStringが実装される
val name = toString
// DNAクラスには自由にメソッドを定義できる
def complement = DNA.complement(code)
}
</code></pre>
</div>
<p>このように定義すると、パターンマッチが問題なく使えるし、complementなど機能を充実させることもできる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val l : DNA = DNA.G
l match {
case DNA.A => ...
case DNA.C => ...
case DNA.G => ...
case DNA.T => ...
case DNA.N => ...
}
</code></pre>
</div>
Scalaプロジェクトの作成
2012-06-28T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/28/create-a-scala-project
<p><strong>ここに書いてあることを手早く実行するには、<a href="http://xerial.org/scala-cookbook/recipes/2012/11/29/scala-in-15-minutes">15分で始めるScala</a>がおすすめです。(2013年1月)</strong></p>
<h2 id="sbt">sbt</h2>
<p>Scalaのコンパイル、テストの実行にはsbt (Simple Build Tool) (全然simpleではないが!) を使うのが2012年現在でのbest practice. IDEではあまりコンパイルしない。</p>
<ul>
<li><a href="https://github.com/harrah/xsbt/wiki/Getting-Started-Welcome">SBT Getting Started Guilde</a></li>
</ul>
<h3 id="sbtでできること">sbtでできること</h3>
<ul>
<li>Scalaのコンパイル</li>
<li>ライブラリの自動ダウンロード</li>
<li>コードライブラリの作成
<ul>
<li>Scala, Javaで動くものはすべて使える</li>
</ul>
</li>
<li>作成したライブラリを公開サーバーにアップロードする</li>
<li>テストの実行</li>
</ul>
<h2 id="sbtを使ったおすすめの最小構成">sbtを使ったおすすめの最小構成</h2>
<p>GitHub <a href="https://github.com/xerial/scala-cookbook/tree/min-project">https://github.com/xerial/scala-cookbook/tree/min-project</a> にすぐScalaの開発を始めるためのコードサンプルが置いてあります。</p>
<div class="highlighter-rouge"><pre class="highlight"><code># min-projectブランチをmyprojectフォルダ内に取得
$ git clone git://github.com/xerial/scala-cookbook.git -b min-project myproject
$ cd myproject
# プロジェクトに必要なファイルをダウンロード、コンパイル、実行
$ bin/sbt run
</code></pre>
</div>
<h3 id="ファイルフォルダ構成">ファイル・フォルダ構成</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>bin/sbt sbtを実行するスクリプト (Windowsの場合は、sbt.bar)
bin/sbt-launch.jar sbt本体
src/main/scala Scala/Javaのソースコード置き場
src/main/resources プログラム中で必要なデータファイルなど
src/test/scala テストコード置き場
src/test/resources テスト時に必要なサンプルデータファイルなど
project/Build.scala プロジェクトの設定
project/Project.scala 配布可能なパッケージを作成する
project/build.sbt sbtのプラグインの設定
lib mavenなどで見つからないライブラリ(jar)の置き場
.gitignore gitで管理しないファイルの設定
</code></pre>
</div>
<h3 id="プロジェクトの定義">プロジェクトの定義</h3>
<p><code class="highlighter-rouge">project/Build.scala</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>import sbt._
import Keys._
object ProjectBuild extends Build {
lazy val root = Project(
id ="sample-project", // Set your project name here (artifact-id)
base = file("."),
settings =
Defaults.defaultSettings
++ Seq(PackageTask.packageDistTask)
++ PackageTask.distSettings
++ Seq(
scalaVersion := "2.9.2",
organization := "org.utgenome.sample", // groupidを設定
version := "1.0-SNAPSHOT",
scalacOptions ++= Seq("-encoding", "UTF-8", "-deprecation", "-unchecked"),
parallelExecution := true,
crossPaths := false,
libraryDependencies ++= Seq(
"org.codehaus.plexus" % "plexus-classworlds" % "2.4",
"org.scalatest" %% "scalatest" % "2.0.M1" % "test"
// Add other libraries here
)
)
)
}
</code></pre>
</div>
<h3 id="ライブラリの追加">ライブラリの追加</h3>
<ul>
<li><a href="http://search.maven.org/">Maven Repository Search</a> で必要なライブラリの、group id, artifact id, version名を調べる。</li>
<li>Build.scalaの<code class="highlighter-rouge">libraryDependencies</code>に追加</li>
</ul>
<p>例:<a href="http://www.xerial.org/trac/Xerial/wiki/SQLiteJDBC">sqlite-jdbc</a> (SQLiteデータベースをJava/Scalaで使うライブラリ)を追加</p>
<div class="highlighter-rouge"><pre class="highlight"><code>libraryDependencies ++= Seq(
(他のライブラリ...),
"org.xerial" % "sqlite-jdbc" % "3.7.2"
)
</code></pre>
</div>
<h3 id="intellijのプロジェクトの作成">IntelliJのプロジェクトの作成</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>$ bin/sbt gen-idea
</code></pre>
</div>
<p>ライブラリの追加を行うごとにこのコマンドを実行するとよい。IntelliJでプロジェクトのリロードが必要になる。</p>
<h3 id="ライブラリの作成">ライブラリの作成</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>$ bin/sbt publish-local
</code></pre>
</div>
<p><code class="highlighter-rouge">$HOME/.ivy2/local/(group id)/(artifact id)-(version)</code>以下に、コードライブラリ(jar, javadoc, source codeのjarなど)が作成される。作成されたものにテストコードは含まれない。</p>
<p>group idは、自分の持っているドメイン名に対応するものを使うのが慣習。<code class="highlighter-rouge">utgenome.org</code>を保有しているなら、<code class="highlighter-rouge">org.utgenome</code>がgroup id。</p>
<h2 id="実行可能な形態での配布">実行可能な形態での配布</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>$ bin/sbt package-dist を実行すると、target/distフォルダ内にそのまま配布できる形のプログラムができあがる。
</code></pre>
</div>
<h3 id="フォルダの内容">フォルダの内容</h3>
<p><code class="highlighter-rouge">target/dist</code>の中身は以下のようになっている。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>bin/launch 実行用スクリプト
bin/classworld.conf classworldの設定ファイル。どのmain関数を呼ぶか、
どのフォルダのライブラリを使うかが記述されている。
lib/scala-library.jar scalaのlibrary本体
lib/classworld-2.4.jar 各種jarファイルを読み込むためのライブラリ。
launchから呼び出される。
lib/sample-project-1.0-SNAPSHOT.jar
作成したプログラム
VERSION プログラムのversion情報が書かれている
</code></pre>
</div>
<p><code class="highlighter-rouge">bin/launch</code>、<code class="highlighter-rouge">bin/classworld.conf</code>は、<code class="highlighter-rouge">src/script</code>以下に含まれている。プログラムの名前を変更したい場合は、 <code class="highlighter-rouge">src/script/launch</code>を<code class="highlighter-rouge">src/script/(your program name)</code>などに変更すること。プログラムのエントリポイント(main関数の場所)を変更するには、<code class="highlighter-rouge">src/script/classworld.conf</code>の内容を変更するとよい。</p>
Scalaを学ぶ
2012-06-28T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/28/scala-references
<h2 id="scala">Scala</h2>
<ul>
<li>
<p><a href="http://www.artima.com/shop/programming_in_scala">Programming in Scala (2nd Ed)</a>
Scalaの開発者(Martin Odersky)らによる参考書。おそらくこれが一番良い教科書。CSの素養があればScalaのデザインについてより理解が深まる本。</p>
</li>
<li><a href="http://docs.scala-lang.org/">Scala Documentation</a>
<ul>
<li><a href="http://docs.scala-lang.org/overviews/collections/introduction.html">Scala Collections</a></li>
<li><a href="http://docs.scala-lang.org/overviews/core/architecture-of-scala-collections.html">The Architecture of Scala Collections</a></li>
<li><a href="http://docs.scala-lang.org/overviews/parallel-collections/overview.html">Parallel collections</a></li>
</ul>
</li>
<li><a href="http://www.scala-lang.org/api/current/index.html">Scala API</a></li>
<li><a href="http://twitter.github.com/scala_school/">Scala School by Twitter inc.</a></li>
</ul>
<h2 id="computer-sciences">Computer Sciences</h2>
<ul>
<li><a href="http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf">Purely Functional Data Structures</a> by Chris Okasaki
<ul>
<li><a href="http://www.amazon.co.jp/Purely-Functional-Structures-Chris-Okasaki/dp/0521663504">Amazon.com</a>, <a href="http://books.google.co.jp/books?id=SxPzSTcTalAC&dq=%22Purely+Functional+Data+Structures%22&printsec=frontcover&source=bn&hl=ja&ei=xCc2S_2uDcGHkQX--_mDCQ&sa=X&oi=book_result&ct=result&resnum=4&ved=0CCQQ6AEwAw#v=onepage&q&f=false">Google Books</a></li>
<li>関数型言語でimmutableで性能の良いデータ構造をどうデザインするか</li>
<li>Listなど、同等の実装がScalaでも使われている</li>
<li>Amortized complexity (償却計算量) の考え方が基本</li>
</ul>
</li>
<li><a href="http://www.amazon.com/Introduction-Algorithms-Third-Edition-ebook/dp/B007CNRCAO/ref=tmm_kin_title_0">Introuction to Algorithms. Third Edition for Kindle</a>
<ul>
<li>アルゴリズムの代表的教科書。研究室でも読書会を行っている</li>
<li>この本を一通り読めば、十分な基礎力が付く</li>
<li>あとは現場の問題(生物学など)に応用あるのみ</li>
</ul>
</li>
</ul>
<h3 id="other-resources">Other resources</h3>
<ul>
<li><a href="https://github.com/harrah/xsbt/wiki">SBT (simple build tool)</a> - Scalaのコードをビルドするのに(今のところ)一番便利。</li>
<li><a href="http://www.scalatest.org/">ScalaTest</a>: Tools for unit testing and tests by specifications. - Scalaでテストコードを書く。unit testingから、behaviour driven development (BDD), tests by specificationsなど、最近流行している形態のテストコードをサポートしている。</li>
<li>How to use Git: <a href="http://progit.org/">ProGit</a></li>
<li><a href="http://help.github.com/git-cheat-sheets/">Git Cheat Sheet</a></li>
</ul>
Scalaの文法一覧
2012-06-28T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/28/grammar
<p><a href="http://docs.scala-lang.org/cheatsheets/">Scala Cheet Sheets</a> (Licensed by Brendan O’Connor under a CC-BY-SA 3.0 license)の和訳。</p>
<table>
<thead>
<tr>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td><h4 id="variables">変数 variables</h4></td>
<td> </td>
</tr>
<tr>
<td><code class="highlighter-rouge">var x = 5</code></td>
<td>変数</td>
</tr>
<tr>
<td><span class="label success">Good</span> <code class="highlighter-rouge">val x = 5</code><br /> <span class="label important">Bad</span> <code class="highlighter-rouge">x=6</code></td>
<td>定数</td>
</tr>
<tr>
<td><code class="highlighter-rouge">var x: Double = 5</code></td>
<td>型を明示</td>
</tr>
<tr>
<td><h4 id="functions">関数 functions</h4></td>
<td> </td>
</tr>
<tr>
<td><span class="label success">Good</span> <code class="highlighter-rouge">def f(x: Int) = { x*x }</code><br /> <span class="label important">Bad</span> <code class="highlighter-rouge">def f(x: Int) { x*x }</code></td>
<td>関数の定義 <br /> 隠れた誤り:Unitを返す関数になってしまっている</td>
</tr>
<tr>
<td><span class="label success">Good</span> <code class="highlighter-rouge">def f(x: Any) = println(x)</code><br /> <span class="label important">Bad</span> <code class="highlighter-rouge">def f(x) = println(x)</code></td>
<td>関数の定義 <br /> 構文の誤り。関数定義の引数にはすべて型が必要</td>
</tr>
<tr>
<td><code class="highlighter-rouge">type R = Double</code></td>
<td>型に別名(alias)をつける</td>
</tr>
<tr>
<td><code class="highlighter-rouge">def f(x: R)</code> vs.<br /> <code class="highlighter-rouge">def f(x: => R)</code></td>
<td>値呼び出し(call-by-value) <br /> 名前呼び出し(call-by-name) 遅延評価されるパラメータ</td>
</tr>
<tr>
<td><code class="highlighter-rouge">(x:R) => x*x</code></td>
<td>無名関数(anonymous function)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">(1 to 5).map(_*2)</code> vs.<br /> <code class="highlighter-rouge">(1 to 5).reduceLeft( _+_ )</code></td>
<td>無名関数:<code class="highlighter-rouge">_</code> は 関数の引数に順々にマッチする</td>
</tr>
<tr>
<td><code class="highlighter-rouge">(1 to 5).map( x => x*x )</code></td>
<td>無名関数で同じ引数を二度使う場合は、名前を付けなくてはならない</td>
</tr>
<tr>
<td><span class="label success">Good</span> <code class="highlighter-rouge">(1 to 5).map(2*)</code><br /> <span class="label important">Bad</span> <code class="highlighter-rouge">(1 to 5).map(*2)</code></td>
<td>無名関数:中置記法を使う。誤解を避けるには <code class="highlighter-rouge">2*_</code> を使うとよい。</td>
</tr>
<tr>
<td><code class="highlighter-rouge">(1 to 5).map { val x=_*2; println(x); x }</code></td>
<td>無名関数:ブロック記法では、最後の式の評価結果が返る.</td>
</tr>
<tr>
<td><code class="highlighter-rouge">(1 to 5) filter {_%2 == 0} map {_*2}</code></td>
<td>無名関数:ブロック記法のパイプライン (括弧記法でも使える).</td>
</tr>
<tr>
<td><code class="highlighter-rouge">def compose(g:R=>R, h:R=>R) = (x:R) => g(h(x))</code> <br /> <code class="highlighter-rouge">val f = compose({_*2}, {_-1})</code></td>
<td>無名関数:複数のブロックを渡す。外側の括弧{}が必要.</td>
</tr>
<tr>
<td><code class="highlighter-rouge">val zscore = (mean:R, sd:R) => (x:R) => (x-mean)/sd</code></td>
<td>カリー化(引数の一部を取り出した関数を作る)の平易な構文</td>
</tr>
<tr>
<td><code class="highlighter-rouge">def zscore(mean:R, sd:R) = (x:R) => (x-mean)/sd</code></td>
<td>カリー化の平易な構文</td>
</tr>
<tr>
<td><code class="highlighter-rouge">def zscore(mean:R, sd:R)(x:R) = (x-mean)/sd</code></td>
<td>カリー化の簡略構文。しかし、</td>
</tr>
<tr>
<td><code class="highlighter-rouge">val normer = zscore(7, 0.4)_</code></td>
<td>こちらの書き方では最後に<code class="highlighter-rouge">_</code>が必要で、部分関数(引数の一部に値を適用した関数)を作る</td>
</tr>
<tr>
<td><code class="highlighter-rouge">def mapmake[T](g:T=>T)(seq: List[T]) = seq.map(g)</code></td>
<td>汎用(generic)型</td>
</tr>
<tr>
<td><code class="highlighter-rouge">5.+(3); 5 + 3</code> <br /> <code class="highlighter-rouge">(1 to 5) map (_*2)</code></td>
<td>中置記法の簡略</td>
</tr>
<tr>
<td><code class="highlighter-rouge">def sum(args: Int*) = args.reduceLeft(_+_)</code></td>
<td>可変長引数</td>
</tr>
<tr>
<td><h4 id="packages">パッケージ packages</h4></td>
<td> </td>
</tr>
<tr>
<td><code class="highlighter-rouge">import scala.collection._</code></td>
<td>ワイルドカード import.</td>
</tr>
<tr>
<td><code class="highlighter-rouge">import scala.collection.Vector</code> <br /> <code class="highlighter-rouge">import scala.collection.{Vector, Sequence}</code></td>
<td>パッケージ内でクラスを(複数)選択してimport.</td>
</tr>
<tr>
<td><code class="highlighter-rouge">import scala.collection.{Vector => Vec28}</code></td>
<td>クラスの名前を置き換えて import.</td>
</tr>
<tr>
<td><code class="highlighter-rouge">import java.util.{Date => _, _}</code></td>
<td>java.utilからすべてimportするがDateは除く.</td>
</tr>
<tr>
<td><code class="highlighter-rouge">package pkg</code> <em>ファイルの先頭で</em> <br /> <code class="highlighter-rouge">package pkg { ... }</code></td>
<td>パッケージを宣言</td>
</tr>
<tr>
<td><h4 id="data_structures">データ構造 data structures</h2></td>
<td> </td>
</tr>
<tr>
<td><code class="highlighter-rouge">(1,2,3)</code></td>
<td>タプルの表記. (<code class="highlighter-rouge">Tuple3</code>)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">var (x,y,z) = (1,2,3)</code></td>
<td>構造を分解して変数に束縛: タプルはパターンマッチで分解される.</td>
</tr>
<tr>
<td><span class="label important">Bad</span><code class="highlighter-rouge">var x,y,z = (1,2,3)</code></td>
<td>隠れた誤り:各変数にタプル全体が代入される</td>
</tr>
<tr>
<td><code class="highlighter-rouge">var xs = List(1,2,3)</code></td>
<td>リスト (immutable).</td>
</tr>
<tr>
<td><code class="highlighter-rouge">xs(2)</code></td>
<td>添字による要素へのアクセス. (<a href="http://www.slideshare.net/Odersky/fosdem-2009-1013261/27">slides</a>)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">1 :: List(2,3)</code></td>
<td>cons.</td>
</tr>
<tr>
<td><code class="highlighter-rouge">1 to 5</code> <em>以下と同じ</em> <code class="highlighter-rouge">1 until 6</code> <br /> <code class="highlighter-rouge">1 to 10 by 2</code></td>
<td>範囲指定の簡易構文</td>
</tr>
<tr>
<td><code class="highlighter-rouge">()</code> <em>(空の括弧)</em></td>
<td>Unit型だけを受け取る関数引数の型 (C/Javaでいうvoid).</td>
</tr>
<tr>
<td><h4 id="control_constructs">制御構造 control constructs</h4></td>
<td> </td>
</tr>
<tr>
<td><code class="highlighter-rouge">if (check) happy else sad</code></td>
<td>条件分岐</td>
</tr>
<tr>
<td><code class="highlighter-rouge">if (check) happy</code> <em>same as</em> <br /> <code class="highlighter-rouge">if (check) happy else ()</code></td>
<td>条件分岐の簡略</td>
</tr>
<tr>
<td><code class="highlighter-rouge">while (x < 5) { println(x); x += 1}</code></td>
<td>whileループ</td>
</tr>
<tr>
<td><code class="highlighter-rouge">do { println(x); x += 1} while (x < 5)</code></td>
<td>do whileループ</td>
</tr>
<tr>
<td><code class="highlighter-rouge">import scala.util.control.Breaks._</code><br /><code class="highlighter-rouge">breakable {</code><br /><code class="highlighter-rouge"> for (x <- xs) {</code><br /><code class="highlighter-rouge"> if (Math.random < 0.1) break</code><br /><code class="highlighter-rouge"> }</code><br /><code class="highlighter-rouge">}</code></td>
<td>break. (<a href="http://www.slideshare.net/Odersky/fosdem-2009-1013261/21">slides</a>)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">for (x <- xs if x%2 == 0) yield x*10</code> <em>以下と同じ</em> <br /><code class="highlighter-rouge">xs.filter(_%2 == 0).map(_*10)</code></td>
<td>for文による網羅: filter/map</td>
</tr>
<tr>
<td><code class="highlighter-rouge">for ((x,y) <- xs zip ys) yield x*y</code> <em>以下と同じ</em> <br /><code class="highlighter-rouge">(xs zip ys) map { case (x,y) => x*y }</code></td>
<td>for文による網羅: データ構造を分解パターンマッチしながら代入</td>
</tr>
<tr>
<td><code class="highlighter-rouge">for (x <- xs; y <- ys) yield x*y</code> <em>以下と同じ</em> <br /><code class="highlighter-rouge">xs flatMap {x => ys map {y => x*y}}</code></td>
<td>for文による網羅: 直積 cross product を取る</td>
</tr>
<tr>
<td><code class="highlighter-rouge">for (x <- xs; y <- ys) {</code><br /> ` println(“%d/%d = %.1f”.format(x,y, x*y))<code class="highlighter-rouge"><br></code>}`</td>
<td>for文による網羅: 命令型スタイル <br /><a href="http://java.sun.com/javase/6/docs/api/java/util/Formatter.html#syntax">sprintf-style</a></td>
</tr>
<tr>
<td><h4 id="pattern_matching">パターンマッチ pattern matching</h2></td>
<td> </td>
</tr>
<tr>
<td><span class="label success">Good</span> <code class="highlighter-rouge">(xs zip ys) map { case (x,y) => x*y }</code><br /> <span class="label important">Bad</span> <code class="highlighter-rouge">(xs zip ys) map( (x,y) => x*y )</code></td>
<td>caseを関数定義内で使う</td>
</tr>
<tr>
<td><span class="label important">Bad</span><br /><code class="highlighter-rouge">val v42 = 42</code><br /><code class="highlighter-rouge">Some(3) match {</code><br /><code class="highlighter-rouge"> case Some(v42) => println("42")</code><br /><code class="highlighter-rouge"> case _ => println("Not 42")</code><br /><code class="highlighter-rouge">}</code></td>
<td>“v42” は任意のIntの値とマッチする変数名として解釈され、”42”が表示される.</td>
</tr>
<tr>
<td><span class="label success">Good</span><br /><code class="highlighter-rouge">val v42 = 42</code><br /><code class="highlighter-rouge">Some(3) match {</code><br /><code class="highlighter-rouge"> case Some(`v42`) => println("42")</code><br /><code class="highlighter-rouge">case _ => println("Not 42")</code><br /><code class="highlighter-rouge">}</code></td>
<td>”`v42`” のように`で囲むと、既に存在するval <code class="highlighter-rouge">v42</code>と解釈され、”Not 42”が表示される.</td>
</tr>
<tr>
<td><span class="label success">Good</span><br /><code class="highlighter-rouge">val UppercaseVal = 42</code><br /><code class="highlighter-rouge">Some(3) match {</code><br /><code class="highlighter-rouge"> case Some(UppercaseVal) => println("42")</code><br /><code class="highlighter-rouge"> case _ => println("Not 42")</code><br /><code class="highlighter-rouge">}</code></td>
<td>大文字からはじまる<code class="highlighter-rouge">UppercaseVal</code> は既に存在するvalとして扱われ, 新しいパターン変数とは見なされない。<code class="highlighter-rouge">UppercaseVal</code>に入っている値(42)は<code class="highlighter-rouge">3</code>と比較されるので、”Not 42”が表示される.</td>
</tr>
<tr>
<td><h4 id="object_orientation">オブジェクト指向 object orientation</h4></td>
<td> </td>
</tr>
<tr>
<td><code class="highlighter-rouge">class C(x: R)</code> <em>以下と同じ</em> <br /><code class="highlighter-rouge">class C(private val x: R)</code><br /><code class="highlighter-rouge">var c = new C(4)</code></td>
<td>コンストラクタの引数 - private</td>
</tr>
<tr>
<td><code class="highlighter-rouge">class C(val x: R)</code><br /><code class="highlighter-rouge">var c = new C(4)</code><br /><code class="highlighter-rouge">c.x</code></td>
<td>コンストラクタの引数 - public</td>
</tr>
<tr>
<td><code class="highlighter-rouge">class C(var x: R) {</code><br /><code class="highlighter-rouge">assert(x > 0, "positive please")</code><br /><code class="highlighter-rouge">var y = x</code><br /><code class="highlighter-rouge">val readonly = 5</code><br /><code class="highlighter-rouge">private var secret = 1</code><br /><code class="highlighter-rouge">def this = this(42)</code><br /><code class="highlighter-rouge">}</code></td>
<td><br />コンストラクタはクラスのbody.<br />publicメンバを宣言<br />値は取得できるが上書きできないメンバを宣言<br />privateメンバを宣言<br />代替コンストラクタ</td>
</tr>
<tr>
<td><code class="highlighter-rouge">new{ ... }</code></td>
<td>無名クラス</td>
</tr>
<tr>
<td><code class="highlighter-rouge">abstract class D { ... }</code></td>
<td>抽象クラスの定義 (生成できない)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">class C extends D { ... }</code></td>
<td>継承したクラスの定義</td>
</tr>
<tr>
<td><code class="highlighter-rouge">class D(var x: R)</code><br /><code class="highlighter-rouge">class C(x: R) extends D(x)</code></td>
<td>継承したときのコンストラクタの引数。 (本当は自動的にパラメータを親に引き継げるようになる用になってほしい)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">object O extends D { ... }</code></td>
<td>singletonを定義. (モジュールのように)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">trait T { ... }</code><br /><code class="highlighter-rouge">class C extends T { ... }</code><br /><code class="highlighter-rouge">class C extends D with T { ... }</code></td>
<td>trait.<br />traitをインターフェースとして使い、実装を提供. コンストラクタの引数を取らない場合. <a href="/scala-cookbook/tutorials/tour/mixin-class-composition.html">mixin-able</a></td>
</tr>
<tr>
<td><code class="highlighter-rouge">trait T1; trait T2</code><br /><code class="highlighter-rouge">class C extends T1 with T2</code><br /><code class="highlighter-rouge">class C extends D with T1 with T2</code></td>
<td>複数のtraitを組み合わせる</td>
</tr>
<tr>
<td><code class="highlighter-rouge">class C extends D { override def f = ...}</code></td>
<td>宣言を上書きするときはoverrideを付ける</td>
</tr>
<tr>
<td><code class="highlighter-rouge">new java.io.File("f")</code></td>
<td>オブジェクトを生成</td>
</tr>
<tr>
<td><span class="label important">Bad</span> <code class="highlighter-rouge">new List[Int]</code><br /> <span class="label success">Good</span> <code class="highlighter-rouge">List(1,2,3)</code></td>
<td>型の誤り:抽象型は生成できない<br />代わりに慣習として型を隠したfactoryを使う</td>
</tr>
<tr>
<td><code class="highlighter-rouge">classOf[String]</code></td>
<td>classの情報を得る</td>
</tr>
<tr>
<td><code class="highlighter-rouge">x.isInstanceOf[String]</code></td>
<td>型があっているか検査 (実行時)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">x.asInstanceOf[String]</code></td>
<td>型のキャスト (実行時)</td>
</tr>
<tr>
<td><code class="highlighter-rouge">x: String</code></td>
<td>型の記述によるチェック (コンパイル時)</td>
</tr>
</tbody>
</table>
ファイルを読む
2012-06-28T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/28/reading-files
<h2 id="scalaiosourceを使う">scala.io.Sourceを使う</h2>
<p>一行ずつデータを読む簡単なプログラムを書きたい場合には以下のように書ける。</p>
<div class="highlighter-rouge"><pre class="highlight"><code># lineに各行のデータが代入される
for(line <- Source.fromFile("file name").getLines) { ... }
</code></pre>
</div>
<p>よりファイルを閉じるタイミングや読み書きの性能等を気にするなら以下を参考に。</p>
<h2 id="バッファを経由して読む">バッファを経由して読む</h2>
<p><a href="http://xerial.org/scala-cookbook/recipes/2012/06/27/loan-pattern">Loan pattern</a>を使う。ファイルの入出力の機能はJavaのライブラリから借りてくる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def open(fileName:String)(body:InputStream => Unit) : Unit = {
// ディスクへの細かなアクセスを避けるため、バッファを介してファイルを読む
val in = new BufferedInputStream(new FileInputStream(fileName))
try
body(in)
finally
in.close // 開けたら閉じる
}
open("myfile.txt") { f =>
val buf = new Array[Byte](8192) // 8kのバッファを用意
def loop {
val readBytes = f.read(buf) // bufferにデータを読み込む
if(readBytes != -1) { // -1が返るとこれ以上データはない
// use read data here
loop
}
}
loop
}
</code></pre>
</div>
<h2 id="一行ずつ読む">一行ずつ読む</h2>
<p><code class="highlighter-rouge">BufferedReader</code>を使うと良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def open(fileName:String)(body:BufferedReader => Unit) : Unit = {
// ディスクへの細かなアクセスを避けるため、バッファを介してファイルを読む
val in = new BufferedReader(new FileReader(fileName))
try
body(in)
finally
in.close // 開けたら閉じる
}
open("myfile.txt") { f =>
def loop {
val line = f.readLine // 一行ずつ読む
if(line != null) { // nullが返ると読み込み終了
// use read data here
loop
}
}
loop
}
</code></pre>
</div>
<h2 id="よりscalaらしい書き方">よりScalaらしい書き方</h2>
<p>上記のコードでは<em>null</em>の扱いに気をつける必要があり、安全ではない。<em>null</em>の使用をクラスの内部に閉じ込め、使う側は<em>null</em>を気にせず一行ずつ操作できる<code class="highlighter-rouge">Iterator[String]</code>を提供する形に書き換える。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// 一行ずつ読み込むiteratorを定義
class LineIterator(in:BufferedReader) extends Iterator[String] {
private var nextLine : String = null
def hasNext = {
if(nextLine == null)
nextLine = in.readLine
nextLine != null
}
def next : String = {
if(hasNext) {
val line = nextLine
nextLine = null
line
}
else
Iterator.empty.next
}
}
def open[U](fileName:String)(body:Iterator[String] => U) {
val in = new BufferedReader(new FileReader(fileName))
try
body(new LineIterator(in)) // Iteratorを返す
finally
in.close // 開けたら閉じる
}
open("myfile.txt") { f =>
for(line <- f) { // Iterator#foreachが使える
// 一行ずつ処理する
}
}
</code></pre>
</div>
<p>Itertorの使用を途中で止めても、loan patternに閉じ込めて実行しているのでファイルがきちんと閉じられる。</p>
プログラムの挙動をテストする
2012-06-28T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/28/scalatest
<p>プログラムが正しく動くかどうかを検証するには以下の方法が考えられます:</p>
<ul>
<li>型が合っているかを確認する (Scalaのコンパイラが検査してくれる)</li>
<li>あらゆる入力に対して正しい結果を得るコードであることを証明する (soundness)。</li>
<li>そのコードで必要な結果をすべて計算できる(completeness)の検証。</li>
</ul>
<p>最後の検証方法を毎回行うのは大変なので(アルゴリズムの論文を書くときには必須ですが)、手軽な方法として</p>
<ul>
<li>コードを動かしてみて結果を確認する</li>
</ul>
<p>このアプローチが経験的にうまくいくことが知られています。</p>
<h2 id="scalatestによるテストコードの作成">ScalaTestによるテストコードの作成</h2>
<p>Scalaでのテストコード作成には</p>
<ul>
<li><a href="http://www.scalatest.org/">ScalaTest</a></li>
<li><a href="http://etorreborre.github.com/specs2/">Specs2</a></li>
</ul>
<p>が有名です。今回は構文が比較的わかりやすいScalaTestについて紹介します。</p>
<h2 id="テストコードの実行">テストコードの実行</h2>
<p><a href="/recipes/2012/06/28/create-a-scala-project">Scalaのプロジェクトの作成</a>の例では、ScalaTestをすぐ使えるようになっています。<code class="highlighter-rouge">libraryDepenedencies</code>に、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>"org.scalatest" %% "scalatest" %% "2.0.M1" % "test"
</code></pre>
</div>
<p>を追加する記述があるのを確認してください。</p>
<div class="highlighter-rouge"><pre class="highlight"><code># テストコードを実行
$ bin/sbt test
# ソースコードのの更新がある度にテストコードを繰り返し実行
$ bin/sbt "~test"
</code></pre>
</div>
<h2 id="テストコードの作成">テストコードの作成</h2>
<p>ScalaTestではいろいろなスタイルでテストコードが作成できます。以下は、<a href="http://www.scalatest.org/scaladoc/1.8/#org.scalatest.WordSpec">WordSpec</a>での例:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// よく使う機能の組み合わせをtraitにまとめておくと便利
trait MySpec extends WordSpec with ShouldMatcher
class FASTATest extends MySpec {
"A parser" should {
"read .gz fasta files" in {
...
}
"read tar.gz fasta files" taggedAs(Tag("debug")) in {
...
}
}
}
</code></pre>
</div>
<p>特定のテストコードを繰り返して実行</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ bin/sbt "~test-only *FASTATest"
</code></pre>
</div>
<h2 id="タグを付けたテストコードのみを繰り返して実行">タグを付けたテストコードのみを繰り返して実行</h2>
<p>ScalaTestのテストコードには、<code class="highlighter-rouge">taggedAs(Tag("tagname"))</code>でタグを付けるこ
とができます。テストを実行する際に、以下のように指定されたタグが付いた
テストのみを実行することができます。一部のコードに集中してデバッグした
いときに便利。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ bin/sbt "~test-only *FASTATest -- -n debug"
</code></pre>
</div>
Scalaのコレクションを使う
2012-06-28T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/28/using-scala-collections
<h2 id="準備">準備</h2>
<h3 id="コードの取得">コードの取得</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>$ git clone git://github.com/xerial/scala-cookbook.git
$ cd scala-cookbook
$ git fetch
$ git checkout lesson1
</code></pre>
</div>
<h3 id="intellijプロジェクトの更新">IntelliJプロジェクトの更新</h3>
<div class="highlighter-rouge"><pre class="highlight"><code># bin/sbt gen-ideaを実行
$ make idea
</code></pre>
</div>
<h3 id="テストコードの実行">テストコードの実行</h3>
<div class="highlighter-rouge"><pre class="highlight"><code># bin/sbt -Dloglevel=debug "~test-only *Lesson1Test" のコマンドを実行
$ make debug test="Lesson1Test"
</code></pre>
</div>
<p>Windows (DOS) プロンプトで実行する場合</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala-cookbook>bin\sbt -Dloglevel=debug "~test-only *Lesson1Test"
</code></pre>
</div>
<p>上記のコマンドで、ソースコードに変更を加えるたびに、コンパイル、テストを実行を自動的に行ってくれる。</p>
<h2 id="課題">課題</h2>
<p>以下の作業をするコードを作成</p>
<ul>
<li>UCSCのDownloadページから遺伝子情報(Annotation database -> refGene.gz) のファイルをダウンロード</li>
<li>ファイルに保存(保存する位置を決めておく。二回目以降は、ファイルがなければダウンロードするコードに)</li>
<li>gzipを解凍しながらtab区切りのテキストをparseして、collectionに格納</li>
<li>作成した遺伝子リストを使って、Array, Map, Set, Tupleの使い方を学ぶ</li>
</ul>
<h3 id="参考資料">参考資料</h3>
<p>時間を見つけて以下の資料を眺めておくと良い:</p>
<ul>
<li>
<p><a href="http://www.scala-lang.org/api/current/index.html">Scala API</a></p>
</li>
<li>
<p><a href="http://docs.scala-lang.org/">Scala Documentation</a></p>
<ul>
<li><a href="http://docs.scala-lang.org/overviews/collections/introduction.html">Scala Collections</a></li>
<li><a href="http://docs.scala-lang.org/overviews/core/architecture-of-scala-collections.html">The Architecture of Scala Collections</a></li>
<li><a href="http://docs.scala-lang.org/overviews/parallel-collections/overview.html">Parallel collections</a></li>
</ul>
</li>
</ul>
<h4 id="データセット">データセット</h4>
<p>ヒトゲノムの遺伝子ファイル:<code class="highlighter-rouge">http://hgdownload.cse.ucsc.edu/goldenPath/hg19/database/refFlat.txt.gz</code>
サンプルデータ:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>C17orf76-AS1 NR_027160 chr17 + 16342300 16345340 16345340 16345340 5 16342300,16342894,16343498,16344387,16344681, 16342728,16343017,16343567,16344444,16345340,
</code></pre>
</div>
<p>各行が、commonName, refSeqName, chr, strand, start, end, cdsStart, cdsEnd, exonCount, exonStarts, exonEnds の順にtab区切りで並んでいる。 exonStarts, exonEndsはmicro formatになっており、comma区切り。ただし、commaが最後に1つ余計についているので注意が必要。</p>
<h3 id="テストコードの実行-1">テストコードの実行</h3>
<p><a href="https://github.com/xerial/scala-cookbook/blob/lesson1/src/test/scala/Lesson1Test.scala"><code class="highlighter-rouge">src/test/scala/Lesson1Test.scala</code></a></p>
<div class="highlighter-rouge"><pre class="highlight"><code># bin/sbt "~test-only *Lesson1Test" -Dloglevel=debugを実行
$ make debug test=Lesson1Test
</code></pre>
</div>
<h3 id="今回のサンプルコード">今回のサンプルコード</h3>
<p><a href="https://github.com/xerial/scala-cookbook/blob/lesson1/src/main/scala/Lesson1.scala"><code class="highlighter-rouge">src/main/scala/Lesson1.scala</code></a></p>
<p>コード中の<code class="highlighter-rouge">debug</code>, <code class="highlighter-rouge">info</code>, <code class="highlighter-rouge">time</code>などのメソッドはScalaコードのデバッグ用に私が普段使っているもの。</p>
<h2 id="データセットの準備">データセットの準備</h2>
<h3 id="遺伝子データをダウンロードする">遺伝子データをダウンロードする</h3>
<p>ほとんどJavaの道具を使っている。チャンネルを開いて、省メモリでファイルに書き出す。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val input = Channels.newChannel(new URL(url).openStream)
val out = new FileOutputStream(outputFile).getChannel
try {
out.transferFrom(input, 0, Integer.MAX_VALUE)
}
finally {
input.close
out.close
}
</code></pre>
</div>
<h3 id="gzipを解凍する">gzipを解凍する</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>def gunzipStream(file: File) = new BufferedInputStream(new GZIPInputStream(new FileInputStream(file)))
</code></pre>
</div>
<p>それぞれのクラスについては、Java APIを参照のこと。</p>
<h3 id="ファイルを一行ずつ読み込む">ファイルを一行ずつ読み込む</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>for (line <- Source.fromInputStream(gunzipStream(refFlat)).getLines) {
// do something here
}
</code></pre>
</div>
<h3 id="遺伝子を表すクラスを定義">遺伝子を表すクラスを定義</h3>
<p>遺伝子はパラメータ数が多いので、クラスを定義すると良い。クラスの定義には変数:型のリストを引数として与えるだけでよい。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class UCSCGene(val name: String,
val refSeqName: String,
val chr: String,
val strand: String,
val start: Int,
val end: Int,
val cdsStart: Int,
val cdsEnd: Int,
val exonCount: Int,
val exonStarts: Array[Int],
val exonEnds: Array[Int]) {
override def toString = "name:%s refSeqName:%s, %s, %s:%d-%d".format(name, refSeqName, strand, chr, start, end)
}
</code></pre>
</div>
<p>クラス定義の詳細については次回以降に。<code class="highlighter-rouge">toString</code>メソッドを定義し、自分の好みのメッセージを表示をさせるようにすると、loggerやIDEでデバッグするときにオブジェクトの内容が表示されるので便利。</p>
<h3 id="遺伝子データの構文解析">遺伝子データの構文解析</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>object UCSCGene {
def parse(line: String): Option[UCSCGene] = {
def splitByComma(s: String): Array[Int] = {
val ss = if (s.endsWith(",")) s.slice(0, s.length - 1) else s
ss.split(",").map(x => x.toInt)
}
val c = line.split("\\t")
if (c.length != 11) {
error("Wrong number of columns:%d\n%s", c.length, line)
// Report None instead of issuing an error
None
}
else {
Some(new UCSCGene(c(0), c(1), c(2), c(3), c(4).toInt, c(5).toInt, c(6).toInt, c(7).toInt, c(8).toInt, splitByComma(c(9)), splitByComma(c(10))))
}
}
}
</code></pre>
</div>
<p>parseする際、データにエラーがあっても例外を飛ばしていない。<a href="http://www.scala-lang.org/api/current/index.html#scala.Option">Option</a>を使うことで、コードの流れを妨げないようにできる。(上記のコードはtry..catchで囲んでよりエラーに強くできますが、簡単のため省略)</p>
<ul>
<li>正しく読めた -> Some(parseした結果)</li>
<li>正しく読めなかった -> None</li>
</ul>
<h2 id="コレクションを使う">コレクションを使う</h2>
<h3 id="コレクションを構築する">コレクションを構築する</h3>
<p>サイズの小さいデータなら、以下のように作成できる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>Array(1, 3, 5)
List("A", "C", "G", "T")
Map(0 -> "A", 1 -> "C", 2 -> "G", 3 -> "T", 4 -> "N")
</code></pre>
</div>
<p>手で書き下せない大きなデータに大しては、Builderを用いてコレクションを作成する</p>
<h3 id="mkstringでコレクションの内容の表示">mkStringで、コレクションの内容の表示</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>Array(1, 3, 5).mkString(", ") // "1, 3, 5"
</code></pre>
</div>
<p>問題:mkStringと同等の関数を作成してみよ。StringBuilderを使うと良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val b = new StringBuilder
b += ...
</code></pre>
</div>
<h3 id="array">Array</h3>
<p>遺伝子情報の配列を作成。Builderに<code class="highlighter-rouge">+=</code>で要素を追加していき、最後に<code class="highlighter-rouge">result</code>で配列を取り出す。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// Create an array of genes
val b = Array.newBuilder[UCSCGene]
// Read the unzipped file line by line
for (line <- Source.fromInputStream(gunzipStream(refFlat)).getLines;
gene <- UCSCGene.parse(line)) { // pattern match is used
b += gene
}
b.result
</code></pre>
</div>
<h4 id="arrayへのアクセスapply-update">Arrayへのアクセス:apply, update</h4>
<div class="highlighter-rouge"><pre class="highlight"><code>val a = Array(0, 1, 3)
</code></pre>
</div>
<p><code class="highlighter-rouge">a(0)</code> は<code class="highlighter-rouge">a.apply(0)</code>のsyntax sugarで、<code class="highlighter-rouge">a(0)=10</code>は<code class="highlighter-rouge">a.update(0, 10)</code>のsyntax sugarになっている。</p>
<h3 id="for-loop">for loop</h3>
<p>上記は二段ループの例。Scalaのforループでは、<a href="http://www.scala-lang.org/api/current/index.html#scala.collection.GenTraversableLike">flatMap</a>が使われている。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>for(x <- list) { ... }
</code></pre>
</div>
<p>は、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>list.foreach(x => ...)
</code></pre>
</div>
<p>あるいは、<code class="highlighter-rouge">yield</code>文(後日解説)があると</p>
<div class="highlighter-rouge"><pre class="highlight"><code>list.flatMap(x => ...)
</code></pre>
</div>
<p>と同等。</p>
<h3 id="option">Option</h3>
<p>Optionの値に対してfor loopを使うと、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>for(line <- Some(x)) { ... }
</code></pre>
</div>
<p>は、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>Some(x).foreach(x => ... )
</code></pre>
</div>
<p>と変換される。Noneの場合はどうなるか?というと、<a href="https://github.com/scala/scala/blob/v2.9.2/src/library/scala/Option.scala#L196">Option#foreach</a>の定義を見てみると、</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def foreach[U](f: A => U) {
if (!isEmpty) f(this.get)
}
</code></pre>
</div>
<p>となっている。従って、Someの値のみがループ中で処理され、Noneの要素は無視されることになる。<a href="http://www.scala-lang.org/api/current/index.html#scala.collection.GenTraversableLike">collect</a>も同様に、for文の本体はpartial function(一部分の入力のみに対して定義される関数)と考えることができる。つまり不正な入力に対して例外処理を書く手間を省ける。</p>
<h3 id="sorting">Sorting</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>def sortGenes(in:Array[UCSCGene]) : Array[UCSCGene] = {
in.sortBy(gene => (gene.chr, gene.start))
}
</code></pre>
</div>
<p>sortBy, sortedなどが使える。 sortByでは、sort keyとして使うデータをTupleにして返す。sortedを使うと、2つの要素を比較するOrdering関数(全順序を定義するもの)を使える。</p>
<ul>
<li>参考 <a href="http://www.scala-lang.org/api/current/index.html#scala.collection.mutable.ArrayOps">ArrayOpsで定義されているsort関連の関数</a></li>
</ul>
<h3 id="map">map</h3>
<p>コレクションのそれぞれの要素に対して関数を適用。</p>
<p>遺伝子名だけを取り出す例:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val genes = loadUCSCGene
val geneNames = genes.map(g => g.name)
</code></pre>
</div>
<h3 id="filter">filter</h3>
<p>コレクションの要素から条件に合うものだけを取り出す:</p>
<p>21番染色体のデータのみを取り出す:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val genesInChr21 = genes.filter(g => g.chr == "chr21")
debug("genes in chr21:\n%s", genesInChr21.take(5).mkString("\n"))
</code></pre>
</div>
<h3 id="reduce">reduce</h3>
<p>要素と要素を合わせてコレクションを縮めていく(reduce).</p>
<p>Exonの数をカウントする。以下はすべて同じ結果になる</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val exonCount = genes.map(_.exonCount).reduce(_ + _)
val exonCount2 = genes.map(_.exonCount).reduce((a, b) => a + b)
val exonCount3 = genes.map(_.exonCount).sum
</code></pre>
</div>
<h3 id="fold">fold</h3>
<p>初期値を与え、それと各々の要素を折り畳んでいく(fold)</p>
<p>遺伝子ごとのExonの数の平均を計算する:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val (count, sum) = genes.foldLeft((0, 0))((s, gene) => (s._1 + 1, s._2 + gene.exonCount))
val exonCountAve = count / sum
</code></pre>
</div>
<h3 id="groupby">groupBy</h3>
<p>遺伝子を染色体ごとにグループ分け。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val geneTable = genes.groupBy(_.chr)
// geneTable("chr21") などでアクセスできる
</code></pre>
</div>
<p>この例では、<code class="highlighter-rouge">Map[String, Array[UCSCGene]]</code>が作成される。</p>
<h3 id="map-1">Map</h3>
<p>key, valueのペアによるデータ構造。keyの値による検索をO(log N)に。</p>
<p>遺伝子名 -> UCSCGene の索引を作る:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val geneIndex = {
val b = Map.newBuilder[String, UCSCGene]
for(g <- genes) {
b += g.name -> g
b += g.refSeqName -> g
}
b.result
}
val hox1 = geneIndex("HOXA1")
</code></pre>
</div>
<p>Scalaに限らず一般のプログラミングでも、mutable(変更可能)な変数はなるべく表に出さずに使うのがバグを減らす秘訣。builderクラスの中身は変化しうるので、<code class="highlighter-rouge">geneIndex</code>の作成時には、コードブロックで囲んで、builderクラスの使用を外側から隠すようにしている。</p>
<h3 id="set">Set</h3>
<p>重複を許さない集合を扱うときに使う。</p>
<p>染色体名の集合を計算:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val chrSet = {
val b = Set.newBuilder[String]
for(g <- genes) b += g.chr
b.result
}
</code></pre>
</div>
<p>特定の染色体名のみを取り出す:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val chrNamePattern = """chr([0-9]+|[XY])""".r.pattern
val commonChrSet = chrSet.filter(chr => chrNamePattern.matcher(chr).matches())
</code></pre>
</div>
<h3 id="tuple">Tuple</h3>
<p>遺伝子情報の一部だけを取り出す</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val tuples = genes.map(g => (g.name, g.chr, g.strand, g.start, g.end))
</code></pre>
</div>
<p>Tupleはあえてクラスを作るまでもないときに、簡易データ構造として使われる。データ操作が入り組んでくると、クラスを作成しパラメータに名前を与えてあげる方が可読性が良くなることも多い。</p>
<p>tupleの各要素には、_1, _2, …などでアクセスし、要素をコレクションとして辿るには<code class="highlighter-rouge">tuple.productIterator</code>を呼び出す。</p>
<h2 id="並列化">並列化</h2>
<h3 id="parallel-collection">Parallel collection</h3>
<p>Scalaでのマルチコア並列化は驚くほど簡単。コレクションの<code class="highlighter-rouge">par</code>関数を呼び出すだけ。</p>
<p>遺伝子データをテキストに書き出す例:</p>
<p>single coreで実行</p>
<div class="highlighter-rouge"><pre class="highlight"><code>genes.map(_.toString)
</code></pre>
</div>
<p>multi core で実行</p>
<div class="highlighter-rouge"><pre class="highlight"><code>genes.par.map(_.toString)
</code></pre>
</div>
<p>実行時間を比較してみよう。</p>
<ul>
<li>Java での実行時間の計測は、JVMの実行時最適化や、GCなどの影響により、コードの実行順に大きく左右される。ベンチマークを取るときは、コードの実行順を入れ替える、何十回か計算を繰り返して平均を取るなどの工夫が必要。サンプルコード中の<code class="highlighter-rouge">time(...)</code>, <code class="highlighter-rouge">block(...)</code>はそのようなベンチマークを取る手助けをしてくれる。repeat回数を指定できる。</li>
</ul>
<p>コードの実行時間を計測。3回繰り返す。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>time("gene report", repeat=3) {
block("single core") {
val geneReport = genes.map(_.toString)
}
block("parallel") {
val geneReport = genes.par.map(_.toString)
}
}
</code></pre>
</div>
<p>計測結果 (4 coresの場合)
[TimeMeasure$]
[gene report] total:1.529 sec., count:3, avg:0.510 sec., min:0.322 sec., max:0.873 sec.
[single core] total:1.173 sec., count:3, avg:0.391 sec., min:0.236 sec., max:0.697 sec.
[parallel] total:0.350 sec., count:3, avg:0.117 sec., min:0.086 sec., max:0.171 sec.</p>
インデックス付きのループ
2012-06-28T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/28/loop-with-index
<p>配列へのアクセス、要素のrankなど、添字(インデックス)を使いたい場合、</p>
<p>C++/Javaなどでの書き方</p>
<div class="highlighter-rouge"><pre class="highlight"><code>for(int i=0; i<10; ++i) {
printf("%d-th element:%s\n", i, array[i])
}
</code></pre>
</div>
<p>Scalaでも添字を使うことはできる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>val l = Array("A", "B", "C")
for(i <- 0 until l.length)
println("%d-th element:%s".format(i, l(i)))
</code></pre>
</div>
<p>ここで<code class="highlighter-rouge">zipWithIndex</code>を使うと、添字の指定や配列の長さの範囲の指定が省けて便利。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>for((elem, i) <- l.zipWithIndex)
println("%d-th element:%s".format(i, elem))
</code></pre>
</div>
<p><code class="highlighter-rouge">zipWithIndex</code>の動作</p>
<div class="highlighter-rouge"><pre class="highlight"><code>scala> val l = Array("A", "B", "C")
l: Array[java.lang.String] = Array(A, B, C)
scala> l.zipWithIndex
res0: Array[(java.lang.String, Int)] = Array((A,0), (B,1), (C,2))
</code></pre>
</div>
<p>forループ内では<code class="highlighter-rouge">(elem, i)</code>と<code class="highlighter-rouge">(A, 0), ...</code>のパターンマッチが行われている。</p>
Scala Quick Start
2012-06-27T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/27/scala-quick-start
<h3 id="サンプルコードの取得">サンプルコードの取得</h3>
<p>Gitの設定</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ git config --global core.eol lf
# Windowsで改行文字がCRLFに変換されるのを防ぐ
$ git config --global core.autocrlf false
</code></pre>
</div>
<p>サンプルコードの取得</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ git clone git://github.com/xerial/scala-cookbook.git
$ cd scala-cookbook
# lesson0 branchのコードを取り出す
$ git checkout lesson0
# scalaコードの実行に必要なライブラリをダウンロードし、
# target/distにプログラム全体を作成後、$HOME/local以下にインストール
$ make install
# scalaコードを実行するスクリプトを起動
$ ~/local/bin/scala-cookbook
Hello Scala Cookbook!
</code></pre>
</div>
<ul>
<li>
<p>Java 1.6以上が必要。Macでgitをインストールするには、<a href="http://www.macports.org/">Mac Ports</a>をインストール後、<code class="highlighter-rouge">sudo port install git-core</code>とする。Windowsで頑張る場合は、<a href="http://www.cygwin.com">cygwin</a> をインストール(インストール時に、GNU Make, git, sshなどを同時にインストールすること)。コンソールはminttyが良い。</p>
</li>
<li>
<p>Windowsユーザーでcygwinを使ったmake installがどうしてもうまく動かない場合。コマンドプロンプトより、<code class="highlighter-rouge">bin\sbt</code>を起動してもよい。</p>
</li>
</ul>
<h3 id="intellij-ideaをインストールする">IntelliJ IDEAをインストールする</h3>
<p><a href="http://www.jetbrains.com/idea/">IntelliJ IDEA</a> Community Edition をダウンロード。2012年6月の時点で最強のScala開発環境。ただし、Scalaで開発を始めるにはプラグインのインストールが必要。</p>
<ul>
<li><code class="highlighter-rouge">File</code> -> <code class="highlighter-rouge">Settings</code> -> <code class="highlighter-rouge">Plugins</code> -> <code class="highlighter-rouge">Scala</code> にチェックを入れる</li>
</ul>
<p><img src="http://xerial.org/scala-cookbook/capture/lesson0/plugin.png" alt="plugin" /></p>
<p>Eclipseを使いたい場合は、<a href="http://scala-ide.org/">Scala IDE for Eclipse</a>をインストールすると良い。</p>
<h4 id="改行文字の設定">改行文字の設定</h4>
<ul>
<li><code class="highlighter-rouge">File</code> -> <code class="highlighter-rouge">Settings</code> -> <code class="highlighter-rouge">Code Style</code> -> <code class="highlighter-rouge">General</code> -> <code class="highlighter-rouge">Line separator (for new files)</code> でUNIXを選択する。</li>
</ul>
<h3 id="intellij-のプロジェクトファイルを作成">IntelliJ のプロジェクトファイルを作成</h3>
<div class="highlighter-rouge"><pre class="highlight"><code># bin/sbt gen-idea を実行
$ make idea
</code></pre>
</div>
<p>File -> Open Project で、scala-cookbookのフォルダを選択</p>
<p>File -> Project Structure -> Project SDK を確認。赤文字になっている場合、New -> JSDKを選択し、JDKがインストールされているフォルダを選択する。<code class="highlighter-rouge">C:\Program Files\Java\jdk1.7.0</code> (Windows), <code class="highlighter-rouge">/Library/Java/Home</code> (MacOS X)など。</p>
<h4 id="scala-cookbookの中身">scala-cookbookの中身</h4>
<p><code class="highlighter-rouge">src/main/scala/ScalaCookbook.scala</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>package xerial.scb
object ScalaCookbook {
def main(args:Array[String]) {
println("Hello Scala Cookbook!")
}
}
</code></pre>
</div>
<p>上記のコードを実行するスクリプトが<code class="highlighter-rouge">$HOME/local/bin/scala-cookbook</code>としてインストールされる。</p>
<p>main関数の中身を書き換えて、make installを実行すると再コンパイルされる。
# bin/sbt package-distを実行後、target/dist内の内容を$HOME/local以下にコピー
$ make install
$ ~/local/bin/scala-cookbook</p>
<h3 id="scalatestでテストコードを作成する">ScalaTestでテストコードを作成する</h3>
<p>毎回、make installを実行するのは手間なので、テストコードを作成し、そこからプログラムの挙動を確認する。</p>
<ul>
<li>初期設定: IntelliJで <code class="highlighter-rouge">Settings</code> -> <code class="highlighter-rouge">Compiler</code> -> <code class="highlighter-rouge">Scala Compiler</code> -> <code class="highlighter-rouge">Project FSC</code> -> scala-2.9.2 (version 2.9.2)を選択。FSCはFast Scala Compiler. コンパイル時間を短縮してくれる。</li>
</ul>
<p><a href="http://www.scalatest.org/">ScalaTest</a> を使って新しいテストを作成
<img src="http://xerial.org/scala-cookbook/capture/lesson0/newtest.png" alt="scalatest" />
テストを作成するフォルダは、<code class="highlighter-rouge">src/test/scala</code>を選択。プログラム本体とテストコードを分離しておくのが慣習。</p>
<p>Testing libraryではScalaTestを選択する。
<img src="http://xerial.org/scala-cookbook/capture/lesson0/scalatest.png" alt="scalatest" /></p>
<h4 id="テストコード例">テストコード例</h4>
<p><code class="highlighter-rouge">src/test/scala/ScalaCookbookTest.scala</code></p>
<div class="highlighter-rouge"><pre class="highlight"><code>package xerial.scb
import org.scalatest.FunSuite
class ScalaCookbookTest extends FunSuite {
test("run cookbook") {
ScalaCookbook.main(Array.empty)
}
}
</code></pre>
</div>
<h3 id="テストコードを実行する">テストコードを実行する</h3>
<p>テストしたいコードの上で右クリック -> Run … を選択
<img src="http://xerial.org/scala-cookbook/capture/lesson0/runtest.png" alt="runtest" /></p>
<p><img src="http://xerial.org/scala-cookbook/capture/lesson0/testresult.png" alt="testresult" /></p>
<h3 id="テストコードを実行しながら開発する">テストコードを実行しながら開発する</h3>
<p>ソースコードを更新 -> コンパイル -> テストコードを実行 というサイクルを繰り返すときに便利。</p>
<div class="highlighter-rouge"><pre class="highlight"><code># wildcardを用い、特定のテストのみを実行する(test-only)。~は繰り返して実行するときに付ける
$ bin/sbt "~test-only *ScalaCookbookTest"
Using C:\Users\leo\.sbt\0.11.3 as sbt dir, -sbt-dir to override.
[info] Loading project definition from C:\Users\leo\work\git\scala-cookbook\project
[info] Set current project to scala-cookbook (in build file:/C:/Users/leo/work/git/scala-cookbook/)
[info] Compiling 1 Scala source to C:\Users\leo\work\git\scala-cookbook\target\classes...
[info] Compiling 1 Scala source to C:\Users\leo\work\git\scala-cookbook\target\test-classes...
Hello Scala Cookbook!
[info] ScalaCookbookTest:
[info] - run cookbook
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 6 s, completed 2012/06/12 11:28:19
1. Waiting for source changes... (press enter to interrupt)
</code></pre>
</div>
Loan Pattern
2012-06-27T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/27/loan-pattern
<p>プログラミングでは、「リソースを取得したら解放する」パターンが頻出します。例えば、</p>
<ul>
<li>ファイルを開いたら閉じる</li>
<li>dbへのコネクションを開いたら閉じる</li>
<li>ロックを取得したら、リリースする</li>
</ul>
<p>などがあります。コード中でこの「借りたら返す」を確実に行うのが<strong>Loan Pattern</strong>です。</p>
<h2 id="例外安全でない例">例外安全でない例</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>def query(sql:String) = {
val connection = db.getConnection
val result = connection.query(sql) // もしクエリの実行中に例外が発生したら?
connection.close // このコードが確実に呼ばれる保障がない
result
}
</code></pre>
</div>
<h2 id="例外安全だがコードの再利用がしにくい書き方">例外安全だがコードの再利用がしにくい書き方</h2>
<p>try … finallyで囲むと例外(exception)に強いコードが書ける。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def query(sql:String) = {
val connection = db.getConnection
try
connection.query(sql) // クエリの実行中に例外が発生しても。。。
finally
connection.close // このコードは確実に呼ばれる
}
</code></pre>
</div>
<p>しかし、実際にはqueryだけでなくupdateなどもしたいはず。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def update(sql:String) = {
val connection = db.getConnection
try
connection.update(sql)
finally
connection.close
}
</code></pre>
</div>
<p>同じようなコードなのに、繰り返して書かなくてはいけない。</p>
<h2 id="loan-pattern">Loan Pattern</h2>
<p>Scalaではコードブロック(つまり関数)を引数として渡せるので、パターンの再利用が可能</p>
<div class="highlighter-rouge"><pre class="highlight"><code>// loan pattern
def open[A](body:Connection => A) : A = {
val connection = db.getConnection
try
body(connection)
finally
connection.close
}
// loan patternの利用
def query(sql:String) = open(_.query(sql))
def update(sql:String) = open(_.update(sql))
</code></pre>
</div>
<h2 id="関連項目">関連項目</h2>
<p>C++で似たようなパターンを実現するには以下の手法がある</p>
<ul>
<li><a href="http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/scoped_ptr.htm">scoped_ptr</a>は、ブロックから出たときにリソースの解放を行う。constructorで初期化、ブロックを出たときにdestructorが呼ばれるのでリソースの解放ができる。</li>
<li><a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">Wikipedia: RAII (Resource Acquisition Is Initialization)</a></li>
</ul>
ループを書く
2012-06-27T00:00:00+00:00
http://xerial.org/scala-cookbook/recipes/2012/06/27/loops
<p>0, 1, … , 100までの数字の和を求める</p>
<h2 id="while">while</h2>
<div class="highlighter-rouge"><pre class="highlight"><code>var i = 0
var sum = 0
while(i <= 100) {
sum += i
i += 1
}
</code></pre>
</div>
<p>2つのvarが登場しているため不安が残る。少し安全に書くには以下のように関数内に処理を閉じ込めると良い。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def aseries(limit:Int) = {
var i = 0
var sum = 0
while(i <= limit) {
sum += i
i += 1
}
sum
}
aseries(100)
</code></pre>
</div>
<h2 id="recursion-再帰を使う">recursion 再帰を使う</h2>
<p>関数の中で関数を定義しScalaらしいコードに。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>def aseries(limit:Int) = {
def loop(i:Int) : Int = if(i <= limit) i + loop(i+1) else i
loop(0)
}
aseries(100)
</code></pre>
</div>
<p>このような形の再帰は末尾再帰と呼ばれ、Scalaコンパイラは自動的にwhile文を使った式に最適化してくれる。本当に末尾最適化されているか確認するためには、<code class="highlighter-rouge">@tailrec</code>アノテーションをつけておくこと。末尾再帰最適化できない場合コンパイルエラーになる。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>@tailrec
def aseries(limit:Int) = {
def loop(i:Int) : Int = if(i <= limit) i + loop(i+1) else i
loop(0)
}
aseries(100)
</code></pre>
</div>
<h2 id="for-loop">for loop</h2>
<p>for loopはおなじみ。</p>
<div class="highlighter-rouge"><pre class="highlight"><code>var sum = 0
for(i <- 0 to 100)
sum += i
</code></pre>
</div>
<p>より短く,</p>
<div class="highlighter-rouge"><pre class="highlight"><code>var sum = 0
(0 to 100) foreach (sum += _)
</code></pre>
</div>
<p>varの使用を避けてより関数型言語らしく</p>
<div class="highlighter-rouge"><pre class="highlight"><code>(0 to 100) reduce (_ + _)
(0 to 100) fold(0)(_ + _) // 初期値を明示したい場合
</code></pre>
</div>
<ul>
<li>参考: <a href="http://xerial.org/scala-cookbook/recipes/2012/08/31/range">0 until 100の不思議</a></li>
</ul>