Scalaz 7を本格的に使い始めたので、Scalaz 7を包含したコーディング・イディオムの棚卸しをしています。Scala 2.10の基本機能とScalaz 7を併用する前提で、コーディングの局面毎に使用するイディオムを事前に準備しておくわけです。イディオムを事前準備しておくことで、プログラミングの局面局面で即断即決ができるので効率よくプログラミングを進めることができます。またイディオムは利便性や実行速度などの要因を考慮に入れて使い所を絞り込んでおくので、プログラムの品質や性能などの向上も期待できます。
Scalazは、MonadやMonoidといった代数系の概念を軸にした型クラスやや純粋関数型データ構造を提供するライブラリですが、小回りの効いた便利機能も数多く提供しています。これらの便利機能は特にMonadやMonoidといった概念を抜きにして、便利につかえるので「かんたんScalaz」としてまとめていきたいと思います。
今回はBoolean向けの便利機能です。
準備
説明の準備に以下の関数を定義します。
scala> def t: Boolean = true def t: Boolean = true t: Boolean scala> def f: Boolean = false def f: Boolean = false f: Boolean
option
ScalazではBooleanにoptionメソッドを追加しています。optionメソッドは、Booleanがtrueであれば指定された値を返すSomeを、falseであればNoneを返します。
使い方は以下になります。
scala> t option 100 t option 100 res3: Option[Int] = Some(100) scala> f option 100 f option 100 res4: Option[Int] = None
これをScalaネイティブの文法で書くとif式を用いた以下になります。これでも問題ないといえばないのと実効速度は確実に速いので、Scalazのoptionメソッドは無理をして使う必要はありませんが、プログラミング時にはかゆいところに手が届くという感じで便利なんですよね。
if (t) Option(100) else None
たとえば、次のような感じでBooleanがtrueの時の処理を長めに書く時に重宝します。
t option { val a = somework val b = somework(a) somework(b) }
??と!?
ScalazではMonoidという型クラスを提供していますが、これがすこぶる便利なんです。
その便利さの一つが単位元です。Monoidの性質を持つオブジェクトは、単位元という特別なインスタンスが定義されます。この単位元をデフォルト値や初期値として用いることで、プログラミングを簡略化するテクニックがありますが、この実例の一つがBooleanの「??」メソッドと「!?」メソッドです。
「??」メソッドは、Booleanがtrueであれば指定された値を、falseの場合は型の単位元を返します。
具体的には以下のような動きになります。
scala> t ?? 100 t ?? 100 res5: Int = 100 scala> f ?? 100 f ?? 100 res6: Int = 0
Booleanの値がtrueの場合は、指定された値である100が返ります。一方falseの場合は、以下の動きになっています。
- 指定された値「100」の型はInt
- この式全体の型はInt
- Intの単位元は「0」
- Booleanの値がfalseなのでIntの単位元である「0」を返す
このようにMonoidの性質とScalaの型推論のコンビネーションで、非常にコンパクトに目的の式を記述することができるわけです。
Monoidというと敷居が高いので、「かんたんScalaz」の文脈では型ごとに初期値を持っている、ぐらいの捉え方でよいと思います。この「初期値」は、数値系なら「0」、ListなどはNilとなりますので、0や空といった値になると覚えておいて、実際の値は必要に応じて調べるというアプローチでよいでしょう。
?!
「??」メソッドの否定形は「?!」メソッドになります。
scala> t !? 100 t !? 100 res165: Int = 0 scala> f !? 100 f !? 100 res167: Int = 100
? |
Javaで提供されていた3項演算子は、Scalaには取り込まれずif式を使用するという建付けになっています。
scala> if (t) 100 else 200 if (t) 100 else 200 res0: Int = 100
Scalazでは「?」メソッドと「|」メソッドのコンビネーションで3項演算子っぽく記述することが可能です。
scala> t ? 100 | 200 t ? 100 | 200 res1: Int = 100 scala> f ? 100 | 200 f ? 100 | 200 res2: Int = 200
「?」メソッド&「|」メソッドとは別にfoldメソッドというのも用意されていますが、こちらは特段便利になったような感じはしません。if式と比べると実行速度は確実に落ちるので、foldを使うのならif式を使う方がよさそうです。
scala> t fold (100, 200) t fold (100, 200) res9: Int = 100 scala> f fold (100, 200) f fold (100, 200) res10: Int = 200
「?」メソッド&「|」メソッドもif式に比べると実行速度は確実に落ちるので無理をして使うほどのことはありませんが、短くかけるとプログラミングが楽になる局面(式を1行に収めたい等)はあるので、コーディング・イディオムに加えておくのもよいと思います。
参考
Boolean
2012年のブログです。
Booleanについてはあまり認識は変わっていないようです。
ただ、2012年当時とは色々とアプローチが変わった部分もあるので、技術の棚卸しという意味で過去のブログで取り上げた内容も再度取り上げていく予定です。
Monoid
Monoidに関する2012年ごろのブログのまとめです。
Scalazが提供する代数概念の型クラスのうち、MonadはScalaネイティブでも基本機能は持っていますし、Aplicativeはfor式で代替することが可能です。
しかし、Monoidだけは該当する機能がありません。このMonoidが非常に便利なので、これを使うためにScalazを使うという面が大きいです。
諸元
- Scala 2.10.4
- Scalaz 7.0.6
0 件のコメント:
コメントを投稿