Is is possible to improve type inference for partially applied types in Scala?

≯℡__Kan透↙ 提交于 2019-11-30 09:15:18

As pointed out by Ben James, you are looking for Miles Sabin's Unapply trick. Here it is in scalaz repo. Here's traverseU, implemented with its help. Here are some example usages. And here's my sketchy (hopefully correct) implementation for your particular case (note: I've renamed your Applicative to ApplicativeTest not to interfere with Applicative, defined in scalaz):

scalaz> core/console
[warn] Credentials file /home/folone/.ivy2/.credentials does not exist
[info] Starting scala interpreter...
[info] 
Welcome to Scala version 2.9.2 (OpenJDK 64-Bit Server VM, Java 1.7.0_15).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :paste
// Entering paste mode (ctrl-D to finish)

import scalaz._

trait ApplicativeTest[AF[_]] {
  def ap[A, B](a: AF[A])(f: AF[A => B]): AF[B]
  def pure[A](a: A): AF[A]
  def fmap[A, B](a: AF[A])(f: A => B): AF[B]
}

def traverse_[AP, A](xs: Iterable[A])(f: A => AP)(implicit G: Unapply[ApplicativeTest, AP]): G.M[Unit] = {
  (xs :\ G.TC.pure(())) { (x, acc) =>
    val apFunc = G.TC.fmap(G(f(x)))(a => identity[Unit] _)
    G.TC.ap(acc)(apFunc)
  }
}

implicit def optionAp = new ApplicativeTest[Option] {
  def ap[A, B](a: Option[A])(f: Option[A => B]): Option[B] = f flatMap (a map _)
  def pure[A](a: A) = Some(a)
  def fmap[A, B](a: Option[A])(f: A => B) = a map f
}

implicit def eitherAp[L]: ApplicativeTest[({type l[x]=Either[L, x]})#l] =
  new ApplicativeTest[({type l[x]=Either[L, x]})#l] {
    def ap[A, B](a: Either[L, A])(f: Either[L, A => B]): Either[L, B] = f.right flatMap (a.right map _)
    def pure[A](a: A) = Right(a)
    def fmap[A, B](a: Either[L, A])(f: A => B) = a.right map f
  }

implicit def iterAp = new ApplicativeTest[Iterable] {
  def ap[A, B](a: Iterable[A])(f: Iterable[A ⇒ B]): Iterable[B] = f flatMap(a map _)
  def pure[A](a: A) = Iterable(a)
  def fmap[A, B](a: Iterable[A])(f: A ⇒ B) = a map f
}

// Exiting paste mode, now interpreting.

import scalaz._
defined trait ApplicativeTest
traverse_: [AP, A](xs: Iterable[A])(f: A => AP)(implicit G: scalaz.Unapply[ApplicativeTest,AP])G.M[Unit]
optionAp: java.lang.Object with ApplicativeTest[Option]{def pure[A](a: A): Some[A]}
eitherAp: [L]=> ApplicativeTest[[x]Either[L,x]]
iterAp: java.lang.Object with ApplicativeTest[Iterable]

scala> val x = traverse_(1 to 10) {
     |   case 5 => None
     |   case _ => Some(())
     | }
x: Option[Unit] = None

scala> val y = traverse_(1 to 10) {
     |   case 5 => Left("x"): Either[String, Unit]
     |   case _ => Right(())
     | }
y: Either[String,Unit] = Left(x)

I still don't know how to make it infer Either[String, Unit] instead of Product with Serializable with scala.util.Either[String,Unit] other than strictly specify type in one of the cases like I did on this line: case 5 => Left("x"): Either[String, Unit].

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!