Scala: вывод типов и подтипов / типы с более высоким родом - PullRequest
2 голосов
/ 06 февраля 2011

Я играл со Скалазом, чтобы немного погрузиться в скалу. к чтобы понять, как все работает в scala, я сам начал реализовывать различные алгебраические структуры и столкнулся с поведением, о котором говорили люди из Scalaz.

Вот мой пример кода, который реализует функтор:

trait Functor[M[_]] {
  def fmap[A, B](a: M[A], b: A => B): M[B]
}

sealed abstract class Foo[+A]
case class Bar[A]() extends Foo[A]
case class Baz[A]() extends Foo[A]

object Functor {

  implicit val optionFunctor: Functor[Option] = new Functor[Option]{
    def fmap[A, B](a: Option[A], b: A => B): Option[B] = a match {
      case Some(x) => Some(b(x))
      case None => None
    }   
  }

  implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
    def fmap[A, B](a: Foo[A], b: A => B): Foo[B] = a match {
      case Bar() => Bar()
      case Baz() => Baz()
    }   
  }
}

object Main {
  import Functor._

  def some[A](a: A): Option[A] = Some(a)
  def none[A]: Option[A] = None

    def fmap[M[_], A, B](a: M[A])(b: A => B)(implicit f: Functor[M]): M[B] =
      f.fmap(a, b)

  def main(args: Array[String]): Unit = { 
    println(fmap (some(1))(_ + 1)) 
    println(fmap (none)((_: Int) + 1)) 
    println(fmap (Bar(): Foo[Int])((_: Int) + 1))                                                    
  }
}

Я написал экземпляр функтора для Option и фиктивный sumtype Foo. Проблема в том, что scala не может вывести неявный параметр без явной аннотации типа или метода-оболочки

def some[A](a: A): Option[A] = Some(a)

println(fmap (Bar(): Foo[Int])((_: Int) + 1))

Scala выводит типы, такие как Functor [Bar] и Functor [Some], без этих обходных путей.

Почему это? Может ли кто-нибудь указать мне на раздел в спецификации языка, который определяет это поведение?

С уважением, raichoo

1 Ответ

6 голосов
/ 07 февраля 2011

Вы просите компилятор выполнить две задачи: локальный вывод типа (§6.26.4) аргументов типа для fmap и неявный поиск неявного параметра (§7.2) f. Ссылки на Scala Reference .

Все идет примерно так:

fmap[M = ?, A = ?, B = ?](Some(1))(x => x)

// type the arguments of the first parameter section. This is done
// without an expected type, as `M` and `A` are undetermined.
fmap[M = ?, A = ?, B = ?](Some(1): Some[Int])(x => x)(?) 

// local type inference determines `M` and `A`
fmap[Some, Int, B = ?](Some(1): Some[Int])(x => x)(?) 

// move to the second parameter section, type the argument with the expected type
// `Function1[Int, ?]`. The argument has the type `Function1[Int, Int]`
fmap[Some, Int, ?](Some(1): Some[Int])((x: Int) => x)                                                 

// local type inference determines that B = Int
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)

// search local identifiers, and failing that the implicit scope of type `Functor[Some]]`, for an implicit
// value that conforms to `Functor[Some]`
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)(implicitly[Functor[Some]])

Неявный поиск Functor[Some] завершается неудачей; Functor[Option] не соответствует.

...