前回の続き。
Haskellの型クラスとScalaのimplicit parameterの対応について
既存の型クラスに新たなインスタンスを追加する
前回の記事で、最終的に僕の中でimplicit parameterがスッキリとした形で記述出来たので大変満足している。| ´ - ω - ` |
しかし、Haskellの型クラスの特徴である、「後からinstanceを追加できる」と言う要件を満たしているか検証し忘れたので、検証してみた。
Hoge.scalaに対して、別のファイルでMyHoge.scalaを定義する。
package com.qtamaki.typeclass object MyHoge { implicit def myHoge: Hoge[String] = { new Hoge[String] { def _age(a: String) = a + "!!" def _sage(a: String) = a + "..." def _hoge(a: String) = a + a } } }
main側に追記
package com.qtamaki.typeclass import Hoge.intHoge import Hoge.boolHoge import MyHoge.myHoge object Main { def main(args: Array[String]): Unit = { // defined by Library author println(Hoge.age(123)) println(Hoge.age(true)) // MyHoge println(Hoge.age("Hello")) } }
これで、普通に新しいHogeインスタンスが追加できた。
intHogeとboolHogeの例だけでは、「オーバーロードとどう違うの???」と言う気持ちになるが、これなら胸をはってドヤ顔出来ると言うもの。
implicit parameterを使えば、後からライブラリーの利用者視点で次々とインスタンスを追加していくことができる。
様々な型に特化した、xxxHogeを追加しても、呼び出しはHoge.{age|sage|hoge}と一貫している。メソッドに渡す型によって暗黙的に適切な実装が選ばれるというわけだ。素敵!抱いて!
Functorの定義
勢いに乗って、Functorも定義しちゃおう。
package com.qtamaki.typeclass trait Functor[F[_]] { def _fmap[A,B](r: F[A], f: A => B): F[B] } object Functor { implicit def optionFunctor: Functor[Option] = { new Functor[Option] { def _fmap[A,B](r: Option[A], f: (A => B)): Option[B] = r match { case Some(a) => Some(f(a)) case None => None } } } implicit def listFunctor: Functor[List] = { new Functor[List] { def _fmap[A,B](r: List[A], f: (A => B)): List[B] = r match { case Nil => Nil case x::xs => f(x) :: _fmap(xs, f) } } } def fmap[A,B,F[_]](r: F[A])(f: A => B)(implicit ev: Functor[F]): F[B] = { ev._fmap(r, f) } }
快調快調♪
Functorも、traitのメソッドは利用者には必要ないため_fmapと内部的な名前にしている(本当は利用者から隠蔽したいけど無理っぽい。| ´ - ω - ` |)。
これで、ListとOptionに対してFunctorを定義できた。あとは、Functor.fmap呼び出して使うだけだ。
package com.qtamaki.typeclass import Functor.optionFunctor object Main { def main(args: Array[String]): Unit = { val x = Functor.fmap(List(1,2,3))({x => x + 1}) println(x.mkString(",")) val y = Functor.fmap(Some(1))(_ + 1) // コンパイルエラー!!! println(y) } }
あれ?|0_0|)???
List版は呼べるけど、Option版は呼べないぞ?
まーでも、Listは動いてるし、とりあえずこれは宿題っっ。今日はこれまで。(おい