@halcat0x15a あれ(´・ω・`)?じゃあsyntaxの説明記事お願いします!
— Kenji Yoshidaさん (@xuwei_k) 12月 16, 2012
というわけで、Scalaz Advent Calendarの18日目の記事です。
Scalazには多くの型クラスとそのインスタンスが定義されており、それを扱うために、多くの記法が存在します。
この記事では簡単で冗長な記法から、複雑で簡素な記法まで紹介していきます。
インスタンスの取得
implicit valueとして定義されている型クラスのインスタンスは、implicit parameterにより取得が可能です。
そのインスタンスの取得にも様々方法があります。
implicitly
Scala標準ライブラリに定義されている、implicit valueを取得する関数です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.option._ | |
val map = Map('foo -> "bar", 'hoge -> "fuga") | |
implicitly[Apply[Option]].apply2(map get 'foo, map get 'hoge)(_ + _) |
TypeClass
また、Scalazの型クラスにはインスタンスの取得のための関数、TypeClass.applyを使用することができます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Apply[Option].apply2(map get 'foo, map get 'hoge)(_ + _) |
関数呼び出し
ある型クラスの関数を使用するとき、先ほどのようにインスタンスから直接呼び出すことができます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.list._ | |
Bind[List].join(List(List(1, 2), List(3, 4))) |
Ops
しかし、明示的に型クラスのインスタンスを取得するのは冗長です。
Scalazではimplicit conversionを用いて、型クラスのインスタンスをもつオブジェクトに対して暗黙の型変換を提供します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scalaz.syntax.bind._ | |
List(List(1, 2), List(3, 4)).join |
暗黙型変換の他にも、単一のオブジェクトを対象としない型クラスの関数がインポートされます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scalaz.std.anyVal._ | |
Monoid[Int].zero | |
import scalaz.syntax.monoid._ | |
mzero[Int] |
関数定義
関数を定義するとき、implicit parameterを指定する方法が2つあります。
implicit
1つはimplicitを使う方法です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def double[A](a: A)(implicit A: Semigroup[A]) = | |
A.append(a, a) |
Context Bounds
もう1つ、Context Boundsというものが存在します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def doubleCB[A: Semigroup](a: A) = | |
Semigroup[A].append(a, a) |
インスタンスを明示的に扱わない場合はContex Boundsで定義した方が良いでしょう。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def doubleCBS[A: Semigroup](a: A) = a |+| a |
Syntax
大抵の場合の場合はOpsとContex Boundsで短いコードが得られますが、これらを使っても冗長になる場合があります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def zeroTrio[A: Monoid] = | |
(mzero[A], mzero[A], mzero[A]) | |
import scalaz.syntax.pointed._ | |
def nestPoint[M[_]: Pointed, A](a: A) = | |
a.point[M].point[M] |
Scalaでは返り値の型を指定してもimplicit valueを決定することは出来ないので明示的に型を書く必要があります。
このような場合、Syntaxを使うことで明示的に型を指定する必要がなくなります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def zeroTrioS[A](implicit A: Monoid[A]) = { | |
import A.monoidSyntax._ | |
(mzero, mzero, mzero) | |
} | |
def nestPointS[M[_], A](a: A)(implicit M: Pointed[M]) = { | |
import M.pointedSyntax._ | |
point(point(a)) | |
} |
まとめ
短く簡素なコードになるほど、複雑な仕組みが使われていきます。
大抵のものはContex BoundsとOpsで短いコードになるので、積極的に使っていきましょう。
型クラスのインスタンスから直接関数を呼ぶのも良いですが、Syntaxをimportした方が簡素になる場合があることも頭に入れておくと良いでしょう。
0 件のコメント:
コメントを投稿