kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

Scala Days 2014にドワンゴ社のエンジニアとして参加して来ます

Scala Days 2014(2014年6月16日〜2014年6月18日)に参加することは先日のエントリで書いた通りなのですが、今年は正式にドワンゴ社のエンジニアとして参加することになりました。ですので、一部の費用を除いて、必要経費のほとんどが会社から出ることになります。

今年はその分いつもより現地でのエンジニアとの議論や発表の視聴を初め、気合いを入れて行って来たいと思います。滞在記も書き溜めて、帰国後はドワンゴ社のエンジニアブログでScala Days 2014についてリポートする予定です。それなり以上の性能のカメラで写真も豊富に撮ってくる予定ですので、こうご期待!

  • ○○をOdersky教授に聞いてきてもらいたい
  • 発表者の○○さんにこんな質問をして来て欲しい

といった希望もこのコメント欄で受け付けていますので、どうぞよろしくお願いします。


ドワンゴ社は、社内のプロジェクトの新規案件ではかなり積極的にScalaを使っています。たとえば、Developers Summit 2014の発表『Play2/Scalaでドメイン駆動設計を利用した大規模Webアプリケーションのスクラム開発の勘所』にあるように、社内通称ニコニコ生放送2はPlay/Scalaで書かれています。また、私の所属チームも主にScalaを使って開発を行っています。

人材はまだまだ足りていませんので、興味がありましたらどうぞご一報を。Twitter@kmizu宛か@mesoさん宛にメンションでもしていただければと思います。

ドワンゴ社は本物のScalaエンジニアを募集しています。

初学者向けの Scala Tips (7) - objectで名前空間を作る

たとえば、プログラミング言語のパーザを書いていて、プログラムの木構造を次のように表現したいとします。

sealed trait Expression
case class Addition(lhs: Expression, rhs: Expression) extends Expression
case class Subtraction(lhs: Expression, rhs: Expression) extends Expression
case class Multiplication(lhs: Expression, rhs: Expression) extends Expression
case class Division(lhs: Expression, rhs: Expression) extends Expression
case class Number(value: Int) extends Expression

これで問題はないのですが、Expressionはよく使われる単語なので、プログラムの他の部分と衝突する可能性があります。幸いScalaにはpackageがあるので、

package ast
sealed trait Expression extends Expression
case class Addition(lhs: Expression, rhs: Expression) extends Expression
case class Subtraction(lhs: Expression, rhs: Expression) extends Expression
case class Multiplication(lhs: Expression, rhs: Expression) extends Expression
case class Division(lhs: Expression, rhs: Expression) extends Expression
case class Number(value: Int) extends Expression

とすることは可能ですが、もっとわかりやすい方法として、objectで包むという方法が考えられます。上の定義をobjectを使って書き換えると、

object Ast {
  sealed trait Expression
  case class Addition(lhs: Expression, rhs: Expression) extends Expression
  case class Subtraction(lhs: Expression, rhs: Expression) extends Expression
  case class Multiplication(lhs: Expression, rhs: Expression) extends Expression
  case class Division(lhs: Expression, rhs: Expression) extends Expression
  case class Number(value: Int) extends Expression
}

のようになります。参照するときは、Ast.ExpressionAst.SubtractionのようにすればOKです。

ではでは。

初学者向けの Scala Tips (6) - 文字列リテラル中のインデントを整える

これは、気の利いたIDEであれば自動でやってくれるのであえて覚える必要はないのですが、一応。

Scalaでは、複数行に渡る文字列リテラルを次のようにして書く事ができます*1

val foo = """
class Foo {
  def foo(): Unit = {
    println("foo")
  }
}
"""

ここで、見やすさのためにdefの部分をもう一段インデントして、かつ、出力される文字列は変更したくないときがあります。そのようなときは、

val foo = """
  |class Foo {
  |  def foo(): Unit = {
  |    println("foo")
  |  }
  |}""".stripMargin

とすると良いです。これで、|の部分が除去されて、その次のカラムが行頭になるような複数行文字列が生成されます。これはScalaで複数行文字列を意図通りに出力するときのイディオムとして覚えておくと良いでしょう(IntelliJ IDEAなどではこれを自動で出力してくれるますが)。

*1:何故かここではGithub Flavored Markdownがうまく効いていないようです…

Scala Days 2014に行ってきます

今年はドイツのベルリンで6月16日〜6月18日にかけて開催されます。去年よりも発表のバリエーションが豊かで今からどのセッションを見に行こうか と考えると非常に楽しみです。

初学者向けの Scala Tips (5) - パターンマッチと無名関数の組み合わせを簡潔に書く

Scala初学者の方が書くコードには、しばしば以下のようなものが散見されます。

list.map {x =>
  x match {
    case A =>
    case B =>
    case _ =>
  }
}

無名関数を作るための構文である{x => ...}exp match { case ... }を別々に考えるとこのようなコードになるのは無理はありません。しかし、これはもっと簡潔に書くことができます。改良したのが以下のコードです。

list.map {
  case A =>
  case B =>
  case _ =>
}

前者の書き方に比べて断然簡潔ですね。特別な事情がない限り、無名関数の引数を即座にパターンマッチする必要がある場合、後者の書き方を使いましょう。

ちなみに、この書き方を教えると結構びっくりされる方が多いようで、この構文はPartialFunctionのためのものだと思っていた、ということのようです。確かに、この{ case .... }という構文は、PartialFunction[-A, +B]型のオブジェクトを作るためにも使われます。ただし、それが適用されるのは、左辺がPartialFunction型を要求しているときのみ、つまり

  • (代入/初期化)の左辺がPartialFunctionである
  • メソッドの仮引数がPartialFunctionである

時に限られます。それ以外の場合、

list.map {
  case A => /* A */
  case B => /* B */
  case _ => /* _ */
}

というコードは以下のコードと同じように解釈されます。

list.map {x =>
  x match {
    case A => /* A */
    case B => /* B */
    case _ => /* _ */
  }
}

ちなみに、IntelliJ IDEAは前者の形のコードを検出して、後者の形に変換することを提案する機能を持っているのですが、その名前が「Convert match statement to partial function」という名前です。思わず、誤解を招く名前を付けるなよ!とつっこみたくなりました。

初学者向けの Scala Tips (4) - 可変長引数を取る関数にSeq[T]を渡す

TipsというよりFAQの部類ですが、ときどきつまづく方がいるようなので。

Scalaで以下のような可変長引数を取る関数printAllを定義すると、

def printAll(ss: String*): Unit = {
  ss.foreach(println)
}
printAll("BAZ", "FOO", "BAR")
//BAZ
//FOO
//BAR

のように任意個のStringを渡すことができます。問題は、既に

val fooBar = Seq("FOO", "BAR")

のように既にSeq型のオブジェクトが作られている場合。

fooBarをそのまま引数として渡し、printAll(fooBar)としてしまうと、

(snip) error: type mismatch;
 found   : Seq[String]
 required: String
printAll(fooBar)

というエラーが出てしまいます。これを解決するには、

printAll(fooBar:_*)
//FOO
//BAR

のようにすればOKです。このようにすれば、scalacがfooBarを可変長引数に一つずつ渡したものとして扱ってくれます。

初学者向けでない Scalaバッドノウハウ(1) - traitの初期化時にManifest型の値を取得する

ネタが尽きたわけではないが、Manifest絡みで嫌な現象に遭遇したのでメモと回避方法(現在はManifest型をつかうべきではないがそれはおいておく)。

まず、問題として、次のようなコードを書くと実行時例外(unknown error)が発生する(Scala 2.10.4)。

trait M[T] {
  implicit val m: Manifest[T]
}

case class Point(x: Int, y: Int)

object Main extends M[Point] {
  implicit val m: Manifest[Point] = manifest[Point]
  def main(args: Array[String]) {
    json4sObj.extract[Point]
  }
}

このようになる原因は、traitでの初期化でmanifestメソッドを呼び出すとnullが返ってくることにあるようだ(manifestメソッドはscalacで特別な扱いを受けていることに関連していると思われる)。それならと、manifest呼び出しのタイミングを遅らせるように

trait M[T] {
  implicit def m: Manifest[T]
}

case class Point(x: Int, y: Int)

object Main extends M[Point] {
  implicit def m: Manifest[Point] = manifest[Point]
  def main(args: Array[String]) {
    json4sObj.extract[Point]
  }
}

としてみると、今度は

   at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)
    at Main$.m(M.scala:8)

というStackOverflowErrorが発生する。これの回避策だが、

implicit def m

の部分を

implicit def m()

に書き換えればOK。つまり、最終的なコードは以下のようになる。

trait M[T] {
  implicit def m(): Manifest[T]
}

case class Point(x: Int, y: Int)

object Main extends M[Point] {
  implicit def m(): Manifest[Point] = manifest[Point]
  def main(args: Array[String]) {
    json4sObj.extract[Point]
  }
}

これでうまく行く理由、というより、一つ前のコードがうまく行かなかった理由が釈然としないのだが…(コンパイラが暗黙に想定しているimplicitなManifest[T]を上書きしてしまったせいではないかと推測している)