scalazのapply2は全部適用してF[C]を返すけど、1つだけ適用してF[B => C]返す方がいいのではないかと思った。
あと、scalazのap3 ~ ap8いらなくない?
*(A => B => C) => F[B => C] => F[C]だと(A => B => C) => F[C]より余計にオブジェクト生成される可能性があるかもしれない。
import scala.language.higherKinds | |
trait Functor[F[_]]{ | |
def fmap[A, B](fa: F[A])(f: A => B): F[B] | |
} | |
trait Apply[F[_]] extends Functor[F]{ | |
def apply1[A, B](fa: F[A])(f: A => B): F[B] = fmap(fa)(f) | |
def apply2[A, B, C](fa: F[A])(f: (A, B) => C): F[B => C] = apply1(fa)(a => (b => f(a, b))) | |
def apply3[A, B, C, D](fa: F[A])(f: (A, B, C) => D): F[B => C => D] = apply1(fa)(a => b => c => f(a, b, c)) | |
def fapply[A, B](fa: F[A])(f: F[A => B]): F[B] | |
} | |
object Apply{ | |
implicit val optionApply = new Apply[Option]{ | |
override def fmap[A, B](oa: Option[A])(f: A => B): Option[B] = oa.map(f) | |
override def fapply[A, B](fa: Option[A])(f: Option[A => B]): Option[B] = | |
for{ | |
a <- fa | |
g <- f | |
} yield g(a) | |
} | |
implicit class ApplyOps[F[_], A](self: F[A])(implicit val af: Apply[F]){ | |
//Haskellの<$>と同じにしたかったけど、使えなかったから<@>にした | |
def <@>[B](f: A => B): F[B] = af.apply1(self)(f) | |
def <@>[B, C](f: (A, B) => C): F[B => C] = af.apply2(self)(f) | |
def <@>[B, C, D](f: (A, B, C) => D): F[B => C => D] = af.apply3(self)(f) | |
def <*>[B](f: F[A => B]): F[B] = af.fapply(self)(f) | |
} | |
} | |
object Main{ | |
import Apply._ | |
def main(args: Array[String]): Unit = { | |
val f: (Int, Int, Int) => Int = _+_+_ | |
val f2: Option[Int => Int => Int] = Option(1) <@> f | |
val f3: Option[Int => Int] = Option(2) <*> f2 | |
val r: Option[Int] = Option(3) <*> f3 | |
val r2: Option[Int] = Option(3) <*> (Option(2) <*> (Option(1) <@> f)) | |
println(r) //Some(6) | |
println(r2) //Some(6) | |
} | |
} |