Digite Lambda no limite de contexto e a função do alias do tipo
Tive que escrever um contexto vinculado ao Pedido [Opção [T]]
Acontece que a solução foi
def test[T: ({type L[x] = Ordering[Option[x]]})#L](value1: Option[T], value2: Option[T]) = {
val e = implicitly(Ordering[Option[T]].compare(value1, value2))
}
veja Como definir um contexto vinculado a um tipo de tipo superior (construtor de tipo)
Então brinquei um pouco com o tipo lambda para entender melhor, levando-me a escrever a versão sem o tipo lambda:
type L[x] = Ordering[Option[x]]
def testN[T: L](value1: Option[T], value2: Option[T]) = {
implicitly[L[T]].compare(value1, value2)
}
Muitos exemplos do uso do tipo lambda são para construtor de tipo com 2 parâmetros como MAP [K, V].
Nesse caso, não temos esse problema.
Então eu só me pergunto, por que não ter algo assim
def test[T: Ordering[Option]](value1: Option[T], value2: Option[T]) = {
val e = implicitly(Ordering[Option[T]].compare(value1, value2))
}
obviamente não funciona. Acho que entendi tudo, não há nenhum construtor de tipo Ordering[Option[_]]definido.
O que temos em ordem é:
trait OptionOrdering[T] extends Ordering[Option[T]] {
def optionOrdering: Ordering[T]
def compare(x: Option[T], y: Option[T]) = (x, y) match {
case (None, None) => 0
case (None, _) => -1
case (_, None) => 1
case (Some(x), Some(y)) => optionOrdering.compare(x, y)
}
}
implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] =
new OptionOrdering[T] { val optionOrdering = ord }
Como está Ordering[Option[T]]na definição acima, é Ordering[Option[T]] forSome {type T}akka Existencial, portanto, um tipo apropriado, e não um construtor de tipo.
Então, se eu estiver correto, o que fazemos aqui:
({type L[x] = Ordering[Option[x]]})#L
ou aqui:
type L[x] = Ordering[Option[x]]
está definindo um Construtor de tipo Ordering[Option[_]].
Questão 1:
1 - o meu entendimento está correto? é isso que o Type Lambda faz aqui?
2 - Estou um pouco confuso aqui, então alias de tipo é algo que permite criar construtor de tipo a partir da composição de outros construtores de tipo. Em certo sentido, estou tentando entender a função formal do alias de tipo com variável de tipo.
scala> type e0 = Ordering[Option[_]]
defined type alias e0
scala> :kind -v e0
e0's kind is A
*
This is a proper type.
scala> type e1[w] = Ordering[Option[w]]
defined type alias e1
scala> :kind -v e1
e1's kind is F[A]
* -> *
This is a type constructor: a 1st-order-kinded type.
scala>
Respostas
Construtor de tipo anônimo
({type L[x] = Ordering[Option[x]]})#L
é para o construtor de tipo nomeado
type L[x] = Ordering[Option[x]]
que construtor anônimo (valor)
(x: Int) => x + 1
é para o construtor nomeado (valor)
val f = (x: Int) => x + 1
por exemplo
scala> lazy val v: (({type L[x] = Ordering[Option[x]]})#L)[Int] = ???
lazy val v: scala.math.Ordering[Option[Int]] // unevaluated
scala> lazy val v: L[Int] = ???
lazy val v: L[Int] // unevaluated
scala> lazy val v = ((x: Int) => x + 1)(41)
lazy val v: Int // unevaluated
scala> lazy val v = f(41)
lazy val v: Int // unevaluated
Em Scala 3 (Dotty) você poderá substituir a "atrocidade"
Há menos necessidade de um tipo de projetor no dotty de qualquer maneira, porque temos lambdas de tipo nativo em vez da atrocidade envolvendo tipos estruturais.
com bela sintaxe lambda de tipo
Starting dotty REPL...
scala> lazy val v: (({type L[x] = Ordering[Option[x]]})#L)[Int] = ???
lazy val v: Ordering[Option[Int]]
scala> lazy val v: ([x] =>> Ordering[Option[x]])[Int] = ???
lazy val v: Ordering[Option[Int]]
A sintaxe ligada ao contexto
def test[T: ({type L[x] = Ordering[Option[x]]})#L](value1: Option[T], value2: Option[T]) = ???
é equivalente a
def test[T](value1: Option[T], value2: Option[T])(implicit ev: (({type L[x] = Ordering[Option[x]]})#L)[T]) = ???
que simplifica para
def test[T](value1: Option[T], value2: Option[T])(implicit ev: Ordering[Option[T]]) = ???