Skip to content

Instantly share code, notes, and snippets.

@morikuni
Last active August 29, 2015 14:23
Show Gist options
  • Save morikuni/a7ea220305f56510c60a to your computer and use it in GitHub Desktop.
Save morikuni/a7ea220305f56510c60a to your computer and use it in GitHub Desktop.
Haskell風のApply

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)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment