Untuk meletakkan segala sesuatu dalam konteks: Jawaban ini awalnya diposting di utas lain. Anda melihatnya di sini karena kedua utas telah digabungkan. Pernyataan pertanyaan di utas tersebut adalah sebagai berikut:
Bagaimana mengatasi definisi tipe ini: Pure [({type? [A] = (R, a)}) #?]?
Apa alasan menggunakan konstruksi seperti itu?
Dipotong berasal dari perpustakaan scalaz:
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)
}
//...
}
Menjawab:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
Yang menggarisbawahi dalam kotak setelah P
menyiratkan bahwa itu adalah konstruktor tipe mengambil satu jenis dan mengembalikan jenis lainnya. Contoh konstruktor tipe dengan jenis ini: List
, Option
.
Memberikan List
sebuah Int
, jenis beton, dan memberikan Anda List[Int]
, jenis beton yang lain. Berikan List
sebuah String
dan memberikan Anda List[String]
. Dll
Jadi, List
, Option
dapat dianggap fungsi tingkat jenis arity 1. Secara formal kita katakan, mereka memiliki sejenis * -> *
. Tanda bintang menunjukkan suatu tipe.
Sekarang Tuple2[_, _]
adalah konstruktor tipe dengan jenis (*, *) -> *
yaitu Anda harus memberikannya dua jenis untuk mendapatkan tipe baru.
Sejak tanda tangan mereka tidak cocok, Anda tidak dapat menggantikan Tuple2
untuk P
. Yang perlu Anda lakukan adalah menerapkan sebagian Tuple2
pada salah satu argumennya, yang akan memberi kami konstruktor tipe dengan jenis * -> *
, dan kami dapat menggantinya P
.
Sayangnya Scala tidak memiliki sintaks khusus untuk aplikasi parsial konstruktor tipe, dan karenanya kita harus menggunakan monstrositas yang disebut tipe lambdas. (Apa yang Anda miliki dalam contoh Anda.) Mereka disebut itu karena mereka analog dengan ekspresi lambda yang ada di tingkat nilai.
Contoh berikut mungkin membantu:
// 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:
Level nilai lebih banyak dan pararel level tipe.
// 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>
Dalam kasus yang telah Anda sajikan, parameter type R
adalah fungsi lokal Tuple2Pure
sehingga Anda tidak dapat dengan mudah mendefinisikannya type PartialTuple2[A] = Tuple2[R, A]
, karena tidak ada tempat di mana Anda dapat menempatkan sinonim tersebut.
Untuk menangani kasus seperti itu, saya menggunakan trik berikut yang menggunakan anggota tipe. (Semoga contohnya cukup jelas.)
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)]