Tôi đang cố gắng để cải thiện những suy luận kiểu của traverse_
chức năng trong các mã dưới đây:Có thể cải thiện suy luận kiểu cho các loại được áp dụng một phần trong Scala không?
import scala.language.higherKinds
trait Applicative[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[_]: Applicative, A](xs: Iterable[A])(f: A => AP[Unit]): AP[Unit] = {
val ap = implicitly[Applicative[AP]]
(xs :\ ap.pure(())) { (x, acc) =>
val apFunc = ap.fmap(f(x))(a => identity[Unit] _)
ap.ap(acc)(apFunc)
}
}
implicit def optionAp = new Applicative[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] = new Applicative[({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
}
// silly, but compiles
val x = traverse_(1 to 10) {
case 5 => None
case _ => Some(())
}
println(x)
// also silly, but does not compile
val y = traverse_(1 to 10) {
case 5 => Left("x")
case _ => Right(())
}
println(y)
Chạy trên cho:
/Users/lodea/tmp/traverse.scala:49: error: no type parameters for method traverse_: (f: Int => AP[Unit])(implicit evidence$1: this.Applicative[AP])AP[Unit] exist so that it can be applied to arguments (Int => Product with Serializable with scala.util.Either[String,Unit])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Int => Product with Serializable with scala.util.Either[String,Unit]
required: Int => ?AP
val y = traverse_(1 to 10) {
^
/Users/lodea/tmp/traverse.scala:49: error: type mismatch;
found : Int => Product with Serializable with scala.util.Either[String,Unit]
required: Int => AP[Unit]
val y = traverse_(1 to 10) {
^
two errors found
Để có được nó để biên dịch, tôi phải xác định gõ lập luận để traverse_
:
val y = traverse_[({type l[x]=Either[String, x]})#l, Int](1 to 10) {
case 5 => Left("x")
case _ => Right(())
}
có cách nào tôi có thể cơ cấu lại traverse_
, hoặc bất kỳ phần nào khác của mã, để làm cho suy luận kiểu hoạt động? Khi các loại bắt đầu trở nên phức tạp hơn, điều này sẽ gây khó chịu nhanh chóng.
Miles Sabin phát hiện ra một cách để làm điều này, được sử dụng trong việc thực hiện 'traverseU' trong Scalaz. Điều đó nghe có vẻ giống như những gì bạn đang cố gắng làm. –