Bir şeyleri bağlama koymak için: Bu cevap başlangıçta başka bir konuya gönderildi. Burada görüyorsunuz çünkü iki konu birleştirildi. Söz konusu evrede yer alan soru ifadesi aşağıdaki gibidir:
Bu tür tanımı nasıl çözebilirim: Pure [({type? [A] = (R, a)}) #?]?
Böyle bir yapıyı kullanmanın nedenleri nelerdir?
Snipped scalaz kütüphanesinden geliyor:
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)
}
//...
}
Cevap:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
Sonrasında kutulardaki bir alt çizgi P
, bir tür yapıcısının bir türü aldığını ve başka bir türü döndürdüğünü gösterir. Bu tür tip yapıcılara örnekler: List
, Option
.
Ver List
bir Int
, bir beton türü ve size senkronizasyon List[Int]
, başka somut türü. Ver List
bir String
ve size senkronizasyon List[String]
. Vb.
Yani, List
, Option
1. Resmen dediğimiz Arity tipi seviyede fonksiyonlar olarak kabul edilebilir, bunlar bir tür * -> *
. Yıldız işareti bir türü belirtir.
Şimdi Tuple2[_, _]
tür ile bir tür yapıcı (*, *) -> *
yani yeni bir tür elde etmek için iki tür vermek gerekir.
İmzaları eşleşmediği Tuple2
için bunun yerini alamazsınız P
. Yapmanız gereken , argümanlarından birine kısmen uygulanır Tuple2
, bu da bize nazik bir tür yapıcısı verir * -> *
ve yerine koyabiliriz P
.
Ne yazık ki Scala, tip kurucularının kısmi uygulaması için özel bir sözdizimine sahip değildir ve bu nedenle tip lambda denilen canavarlığa başvurmak zorundayız. (Örneğinizde ne var.) Buna değer denilen lambda ifadelerine benzedikleri için denir.
Aşağıdaki örnek yardımcı olabilir:
// 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>
Düzenle:
Daha fazla değer seviyesi ve tip seviyesi paralelliği.
// 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>
Sunmanız durumunda, type parametresinin R
çalışması için yereldir Tuple2Pure
ve bu nedenle basitçe tanımlayamazsınız type PartialTuple2[A] = Tuple2[R, A]
, çünkü bu eşanlamlıyı koyabileceğiniz bir yer yoktur.
Böyle bir durumla başa çıkmak için, tip üyelerini kullanan aşağıdaki hileyi kullanıyorum. (Umarım örnek kendini açıklayıcıdır.)
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)]