Что это ? тип?

Я пытаюсь реализовать экземплярcats Monad для типа с несколькими параметрами типа. Я посмотрел экземпляр Either котов, чтобы посмотреть, как это там сделано. Часть кода экземпляра Either Monad от котов скопирована ниже:

import cats.Monad

object EitherMonad {
  implicit def instance[A]: Monad[Either[A, ?]] =
    new Monad[Either[A, ?]] {
      def pure[B](b: B): Either[A, B] = Right(b)

      def flatMap[B, C](fa: Either[A, B])(f: B => Either[A, C]): Either[A, C] =
        fa.right.flatMap(f)
    }
}

Не компилируется с ошибкой: error: not found: type ?

Что такое тип ? и как его использовать при создании экземпляров для собственных типов?


person mushroom    schedule 20.12.2015    source источник
comment
? — допустимый символ, в данном случае он такой же, как A.   -  person Matt Ball    schedule 21.12.2015


Ответы (1)


Это специальный синтаксис для так называемых лямбда-выражений типов, который добавляется плагином Kind Projector.

Either[A, ?]

это ярлык для

({type L[X] = Either[A, X]})#L

Весь код обесценивается до

import cats.Monad

object EitherMonad {
  implicit def instance[A]: Monad[({type L[X] = Either[A, X]})#L] = new Monad[({type L[X] = Either[A, X]})#L] {
    def pure[B](b: B): Either[A, B] = Right(b)

    def flatMap[B, C](fa: Either[A, B])(f: B => Either[A, C]): Either[A, C] =
      fa.right.flatMap(f)
  }
}

Лямбда-выражения выглядят пугающе, но по сути это очень простая концепция. У вас есть вещь, которая принимает два параметра типа, например Either[A, B]. Вы хотите предоставить экземпляр монады для Both, но trait Monad[F[_]] принимает только один параметр типа. Но в принципе это нормально, поскольку ваш экземпляр монады в любом случае связан только со вторым («правильным») аргументом типа. Лямбда типа - это просто способ "исправить" аргумент первого типа, чтобы у вас была правильная форма.

Если бы вы сделали то же самое на уровне стоимости, вы бы даже не подумали об этом дважды. Вы получили функцию двух аргументов

val f: (Int, Int) => Int = ...

И что-то, чему вы хотите передать f, что принимает только 1 аргумент

def foo(x: Int => Int) = ...

Единственный способ привести вещи в соответствие — это исправить один из аргументов.

foo(x => f(1, x))

И это именно то, что лямбда типа делает на уровне типа.

person Rüdiger Klaehn    schedule 20.12.2015