• 2014年3月からドワンゴでScala書いてる
  • Scalaz という、Scalaで関数型プログラミングするための怖いライブラリのコミッター
  • 先日勉強会をやった
  • Scalaに必要なJavaの知識はあるけど、普段Javaほとんど書かないのでよくわかりません(>_<)

Scala祭り


((((;゚Д゚)))) !?

2014年7月19日現在


  • 最新versionは4.1
  • Java8に対応

githubの履歴を追った限り


  • 2010年くらいからgithub、それ以前はgoogle code
  • google codeからの履歴引き継いでない
  • なので、最初の開発開始はよくわからないが、少なくとも2009以前
  • github移行後、2014年7月19日までで255コミットしかない

ビルドファイルの歴史など

( ゚Д゚)・・・!?

  • その後sbt(Scala製ビルドツール)が数年使われる
  • Java8がでる
  • Java8対応して欲しい! => 原作者達はあまりやる気ない
  • 新しい人が主導権握って、めでたく(?) Gradle に
  • しかし、今でもテストコードはScala
  • しかもScalacheckという、より関数型なテストライブラリ

やっと本題。中身の紹介

関数オブジェクト

  • F1からF8まで
  • Java8が出る以前から存在するのと、Java7との互換性を保つため、Java8のjava.util.function のものは使われていない

不変データ構造


一部、不変でないデータ構造もあるが、これから挙げるものはすべて不変

不変データ構造


  • List
  • Stream (ScalaのStreamと同じで、不変かつ遅延評価)
  • Option
  • Either

不変データ構造


  • NonEmptyList (必ず要素が1つ以上あることが保証)
  • Validation (Scalazの中にあるあれ)
  • Tree (rose tree)
  • TreeMap (赤黒木)
  • Set (赤黒木)

不変データ構造


  • FingerTree
  • HList
  • Zipper
  • TreeZipper

Javaで無理なく表現できる範囲の一部の
型クラス


  • Equal
  • Ord
  • Semigroup
  • Monoid
  • Hash
  • Show

致命的欠点?



Equal, Hash, Show があるので、大半のclassで、java.lang.Objectの、equals, hashcode, toString がoverrideされてない!!!

並列並行処理


  • Actor (Scalazと同じで型つき)
  • Promise

その他


  • HaskellのQuickcheckの移植
  • Parser
  • Iteratee
  • Trampoline(再帰関数でスタックを溢れさせないようにするためのもの)

ところで・・・

  • Javaで関数型プログラミングといえばJava8のStream!
  • 皆さんJava8のStream使ってますか?

Java8のStreamとの比較



(もしくは、Java8のStreamをdisりに来ました?)
  • Java8のStreamは不変なコレクションではない
  • 同じものを2度使えない、参照透明でないメソッドがあるので、ScalaだとIteratorに近い
  • 良くも悪くも、並列実行のための処理が組み込まれている
  • 遅延評価
  • もちろん関数型の考えは取り入れられているが・・・
  • それでいて、入力や出力を柔軟に制御するための仕組みはなく、すごく複雑な処理が可能なわけでもない


つまりどういうことか?

これだけは今日覚えて帰ってもらいたい

(良し悪しは別にして)Java8のStreamは

関数型言語の一般的なコレクションとは別で色々独特過ぎる!

Java8のStreamのデメリット、もしくは単に好きでない特徴



(もちろん、それぞれの特徴は設計上のトレードオフなので、完全にだめなわけではない)

不変なコレクションでない、副作用のあるメソッドがある



どのメソッドが副作用あるのか把握しないといけない

遅延評価


  • 副作用全く使わない習慣があるHaskellなどなら問題起きにくい。
  • しかし慣れるまで辛い。

遅延評価


  • 副作用なしで書くか、副作用使うなら発生するタイミングを把握する必要
  • そのために、Functional JavaやScalaでは、遅延評価なコレクションとそうでないものを明確に分けて用意

なぜJava8のStreamは遅延評価か?


  • 効率のため?
  • たしかに、中間オブジェクト生成されないほうが効率よい
  • いつでも効率が最重要なのか?
  • (効率はそれほど重要ではなく)手軽にmapやfilterなどができる便利な不変コレクションが欲しいときも多いのでは?
  • つまり他のモダンな言語と同じように、もっと手軽にJavaを使う用途
  • 効率必要ないなら、遅延評価はデバッグがつらいというデメリットのほうが大きいと思う
  • 遅延評価があると、無限な長さのStreamを作って、格好よく扱うというテクニックが可能だったりするが・・・

まとめ

  • もしJava8のStreamに満足できなくて、更に関数型なプログラミングをJavaでやりたくなったら、怖い人達が作ってるFunctional Java使ってみよう
  • 個人的意見として、Java8のStreamは他の関数型言語の似たようなものと比べて独特過ぎるので、あれが普通だと思わないように