Чтобы поместить вещи в контекст: Этот ответ был первоначально отправлен в другой поток. Вы видите это здесь, потому что эти два потока объединены. Заявление вопрос в указанном потоке следующим образом:
How to resolve this type definition: Pure[({type ?[a]=(R, a)})#?] ?
What are the reasons of using such construction?
Snipped comes from scalaz library:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
object Pure {
import Scalaz._
//...
implicit def Tuple2Pure[R: Zero]: Pure[({type ?[a]=(R, a)})#?] = new Pure[({type ?[a]=(R, a)})#?] {
def pure[A](a: => A) = (Ø, a)
}
//...
}
Ответ:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
один Подчеркивание в боксах после P
означает, что конструктор типа принимает один тип и возвращает другой тип. Примеры типовых конструкторов такого типа: List
, Option
.
Дать List
a Int
, конкретный тип, и он дает вам List[Int]
, другой конкретный тип. Дайте List
a String
, и это дает вам List[String]
. И т. Д.
Таким образом, List
, Option
можно рассматривать как функции уровня уровня arity 1. Формально мы говорим, что у них есть вид * -> *
. Звездочка обозначает тип.
В настоящее время Tuple2[_, _]
является конструктором типа с видом (*, *) -> *
, то есть вам нужно дать ему два типа, чтобы получить новый тип.
Поскольку их подписи не совпадают, вы не можете заменить Tuple2
на номер P
. Что вам нужно сделать, это частично применитьTuple2
к одному из своих аргументов, который даст нам конструктор типа с видом * -> *
, и мы можем его заменить на P
.
К сожалению, у Scala нет специального синтаксиса для частичного применения конструкторов типов, поэтому нам нужно прибегнуть к монстрам, называемым типа lambdas. (Что у вас есть в вашем примере.) Они называются так потому, что они аналогичны лямбда-выражениям, которые существуют на уровне значений.
Следующий пример может помочь:
// VALUE LEVEL
// foo has signature: (String, String) => String
scala> def foo(x: String, y: String): String = x + " " + y
foo: (x: String, y: String)String
// world wants a parameter of type String => String
scala> def world(f: String => String): String = f("world")
world: (f: String => String)String
// So we use a lambda expression that partially applies foo on one parameter
// to yield a value of type String => String
scala> world(x => foo("hello", x))
res0: String = hello world
// TYPE LEVEL
// Foo has a kind (*, *) -> *
scala> type Foo[A, B] = Map[A, B]
defined type alias Foo
// World wants a parameter of kind * -> *
scala> type World[M[_]] = M[Int]
defined type alias World
// So we use a lambda lambda that partially applies Foo on one parameter
// to yield a type of kind * -> *
scala> type X[A] = World[({ type M[A] = Foo[String, A] })#M]
defined type alias X
// Test the equality of two types. (If this compiles, it means they're equal.)
scala> implicitly[X[Int] =:= Foo[String, Int]]
res2: =:=[X[Int],Foo[String,Int]] = <function1>
Edit:
Более значение уровня и уровня типа параллелей.
// VALUE LEVEL
// Instead of a lambda, you can define a named function beforehand...
scala> val g: String => String = x => foo("hello", x)
g: String => String = <function1>
// ...and use it.
scala> world(g)
res3: String = hello world
// TYPE LEVEL
// Same applies at type level too.
scala> type G[A] = Foo[String, A]
defined type alias G
scala> implicitly[X =:= Foo[String, Int]]
res5: =:=[X,Foo[String,Int]] = <function1>
scala> type T = World[G]
defined type alias T
scala> implicitly[T =:= Foo[String, Int]]
res6: =:=[T,Foo[String,Int]] = <function1>
В случае, если вы представили, параметр типа R
локален функционировать Tuple2Pure
и поэтому вы не можете просто определить type PartialTuple2[A] = Tuple2[R, A]
, потому что там просто нет места, где вы можете поместить этот синоним.
Чтобы справиться с таким случаем, я использую следующий трюк, который использует члены типа. (Надеюсь, пример не требует пояснений.)
scala> type Partial2[F[_, _], A] = {
| type Get[B] = F[A, B]
| }
defined type alias Partial2
scala> implicit def Tuple2Pure[R]: Pure[Partial2[Tuple2, R]#Get] = sys.error("")
Tuple2Pure: [R]=> Pure[[B](R, B)]
См. [Также] (https://underscore.io/blog/posts/2016/12/05/type-lambdas.html). –