상황에 맞게 :이 답변은 원래 다른 스레드에 게시되었습니다. 두 개의 스레드가 병합되었으므로 여기에서 볼 수 있습니다. 해당 스레드의 질문 내용은 다음과 같습니다.
이 유형 정의를 해결하는 방법 : Pure [({type? [a] = (R, a)}) #?]?
이러한 구성을 사용하는 이유는 무엇입니까?
Snack은 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)
}
//...
}
대답:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
상자의 밑줄은 P
형식 생성자가 한 형식을 취하고 다른 형식을 반환한다는 것을 나타냅니다. 이 종류의 생성자의 예 : List
, Option
.
부여 List
을 Int
, 구체적인 유형을, 그리고 당신을 제공 List[Int]
, 다른 구체적인 유형입니다. 부여 List
을 String
그리고 당신을 제공합니다 List[String]
. 기타.
따라서 List
, Option
1. 공식적으로 우리가 말할 인수에 대응의 타입 수준의 기능으로 간주 될 수있다, 그들은 종류가 * -> *
. 별표는 유형을 나타냅니다.
이제 Tuple2[_, _]
종류가있는 형식 생성자입니다. (*, *) -> *
즉, 새 형식을 얻으려면 두 가지 형식을 지정해야합니다.
자신의 서명이 일치하지 않기 때문에, 당신은 대체 할 수 있습니다 Tuple2
에 대한 P
. 당신이해야 할 일은 인수 중 하나에 부분적으로 적용 Tuple2
하는 것입니다. 이는 우리에게 kind를 가진 타입 생성자를 줄 것이고 * -> *
, 우리는 그것을 대신 할 수 있습니다 P
.
불행히도 스칼라는 형식 생성자의 부분적 적용을위한 특별한 구문을 가지고 있지 않으므로 람다 형식이라는 괴물에 의존해야합니다. (당신의 예에있는 것) 그것들은 그것들이 가치 수준에 존재하는 람다 식과 유사하기 때문에 호출됩니다.
다음 예제가 도움이 될 수 있습니다.
// 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>
편집하다:
더 많은 가치 수준 및 유형 수준 병렬.
// 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>
제시 한 경우, type 매개 변수 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)]