読者です 読者をやめる 読者になる 読者になる

Scalaのコンパクトな便利ライブラリ「Hamsters」を調べてみた

Scala

最近HamstersっていうScalaライブラリを発見しました。関数型っぽいコンテナや機能を提供するものなのですが、非常にコンパクトでなおかつ関数型プログラミングに慣れていなくても簡単に使えるというものです。

github.com

使い方はREADMEを見ればだいたいわかると思いますが、以下のような機能があるようです。

  • Validation
  • OK/KO Monads
  • Monad transformers
  • HLists
  • Union types

ひとつずつ見ていきましょう。

ValidationとOK/KO

ValidationEitherのリストを格納するコンテナ、OK / KOはright-biasなEitherエイリアスで、組み合わせて使います。

こんな感じで全部の結果を保持するか、

val e1 = OK(1)
val e2 = KO("error 1")
val e3 = KO("error 2")

val validation = Validation(e1, e2, e3)
val failures = validation.failures //List[String] : List("error 1", "error 2")
val successes = validation.successes //List[Int] : List(1)

for式で失敗したところで終了するようにできます。

// Stop at first error
for {
  v1 <- e1
  v2 <- e2
  v3 <- e3
} yield(s"$v1-$v2-$v3") //KO("nan")

Monad transformers

ネストしたモナドをひっくり返して扱うことができるやつです。非同期処理を記述するためにFutureを多用しているとお世話になる機会が多いと思います。FutureOptionFutureEitherが用意されています。

def foa: Future[Option[String]] = Future(Some("a"))
def fob(a: String): Future[Option[String]] = Future(Some(a+"b"))

val composedAB: Future[Option[String]] = for {
  a <- FutureOption(foa)
  ab <- FutureOption(fob(a))
} yield ab

型は決め打ちですが、その分あまり難しいことを考えずに使えるんじゃないでしょうか。実装も簡単なので足りないものは自分で作るのもありなんじゃないかと思います。

HLists

要素毎に型を持てるリストです。たくさん値を格納できる可変長のタプルみたいな感じで使えます。フレームワークなんかでは23個以上のパラメータを渡す必要のある関数の引数(23個以上のプロパティを持つケースクラスのapplyメソッドを関数に変換したい場合とか)にも使われますね。

(2.0 :: "hi" :: HNil).filter{
  case s: String if s.startsWith("h") => true
  case _ => false
} //"hi" :: HNil

Union types

複数の型のどれかっていう型を表現できます。たとえばStringもしくはIntを返すメソッドならこんな感じ。

val stringOrIntType = new Union2Type[String, Int]
import stringOrIntType._

def stringOrInt(x: Int): Union2[String, Int] = {
  if(x == 0) "0" else 1
}

stringOrInt(0) match {
  case Union2(Some(x), _) => println("String")
  case Union2(_, Some(x)) => println("Int")
}

うーん、これはちょっと厳しいですかね…。実態は単純に各型の要素をOptionで保持しているだけです。一応Union2からUnion5まで用意されています。

Scalazのような本格的な関数型ライブラリと違って型クラスで拡張できるというようなものではないのですが、使い方も簡単ですしフットプリントも小さいので「Scalaコードをちょっと便利に記述したい」というくらいのモチベーションであればこのくらいのライブラリがちょうどいいのかもしれません。ただ、そういう動機で使うライブラリであれば個人的にはローンパターンとかシンタックスシュガーみたいのもあるといいなぁと思ったりします。

なお、拡張ライブラリとしてTwitter UtilをサポートするものやHListを強化するものなんかも作っているみたいです。