2012年8月24日金曜日

Scala Tips / Option(14) - Tag

今回から使用するScalaのバージョンを2.10.0-M6、Scalazのバージョンを7.0.0-M2に上げました。

今後はScala 2.10 & Scalaz 7でのベストプラクティスという観点で調べていく予定です。

さて、「Option (12) - Monoid」では、OptionがMonoidであることを説明しました。演算子|+|でMonoid演算を行うことができます。

OptionのようなコンテナがMonoidである場合、問題となるのは格納されているオブジェクトへの演算をどのようなセマンティクスで行うのかという点です。

Optionでのデフォルトでは、格納されたオブジェクトがMonoidであることを前提に格納されたオブジェクト間のMonoid演算の結果を、結果のSomeに格納します。

しかし、その他にも「Option (13) - Monoid 短絡OR」に説明した短絡OR的な演算も可能です。Scalaz 6では、トレイトFirstOption、LastOptionを追加し、Optionにfstメソッド、lstメソッドを追加することでOptionのMonoid演算時の短絡ORをサポートしていました。

一方、Scalaz 7ではTagというメカニズムによって短絡ORを実現します。

Tags.First

最初の要素を有効とする短絡OR用のTagとしてTags.Firstが定義されています。

OptionにTags.Firstを「@@」(こういうのは型演算子というのかな。未調査です。)でタグ付けした型を使用します。

まず2つのタグ付したOptionを変数a, bにそれぞれ設定します。タグ付けした場合は型が変わるので「Tag(1.some)」という形で型の調整を行う必要があります。

scala> val a: Option[Int] @@ Tags.First = Tag(1.some)
a: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(1)

scala> val b: Option[Int] @@ Tags.First = Tag(2.some)
b: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(2)

この変数a, bをMonoid演算すると以下のように短絡OR演算が行われSome(1)が結果として返ってきます。

scala> a |+| b
res20: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(1)

変数nにタグ付けしたNoneを設定します。

scala> val n: Option[Int] @@ Tags.First = Tag(none)
n: scalaz.@@[Option[Int],scalaz.Tags.First] = None

Monoid演算のいずれかにNoneが入る場合は、Some側が有効になります。両方Noneの場合は結果もNoneになります。

scala> a |+| n
res27: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(1)

scala> n |+| b
res28: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(2)

scala> n |+| n
res29: scalaz.@@[Option[Int],scalaz.Tags.First] = None

畳込み

タグ付したOptionの集まりに対して畳込みを行うと、MonoidとTagの組合せの効果が分かります。

まず変数cに新しいタグ付けしたSomeを設定します。

scala> val c: Option[Int] @@ Tags.First = Tag(3.some)
c: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(3)

変数a, b, cのListに対してsuml(左からのMonoid畳込み)およびsumr(右からのMonoid畳込み)を行うといずれも結果はSome(1)となりました。

scala> List(a, b, c).suml
res21: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(1)

scala> List(a, b, c).sumr
res22: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(1)

先頭の要素をNoneにした場合は、結果は最初のSomeであるSome(2)となりました。

scala> List(n, b, c).suml
res30: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(2)

scala> List(n, b, c).sumr
res26: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(2)

諸元

  • Scala 2.10.0-M6
  • Scalaz 7.0.0-M2

0 件のコメント:

コメントを投稿