Scala에서 "컨텍스트 바인딩"이란 무엇입니까?


115

Scala 2.8의 새로운 기능 중 하나는 컨텍스트 경계입니다. 컨텍스트 바운드 란 무엇이며 어디에 유용합니까?

물론 먼저 검색을 했지만 ( 예를 들어 this를 찾았 지만) 정말 명확하고 자세한 정보를 찾을 수 없었습니다.


8
또한 모든 유형의 경계에 대한 둘러보기를 확인하십시오. gist.github.com/257758/47f06f2f3ca47702b3a86c76a5479d096cb8c7ec
Arjan Blokzijl

2
이 훌륭한 대답은 / 대조 컨텍스트 경계 및 뷰 경계 비교 stackoverflow.com/questions/4465948/...
아론 Novstrup

이것은 아주 좋은 대답입니다. stackoverflow.com/a/25250693/1586965
samthebest 2014-08-12

답변:


107

이 기사 를 찾았습니까 ? 배열 개선의 맥락에서 새로운 컨텍스트 바인딩 기능을 다룹니다.

일반적으로 컨텍스트 바인딩 이 있는 형식 매개 변수 는 형식입니다 [T: Bound]. 유형 T의 암시 적 매개 변수 와 함께 일반 유형 매개 변수로 확장됩니다 Bound[T].

tabulate0에서 주어진 길이까지의 숫자 범위에 주어진 함수 f를 적용한 결과로부터 배열을 형성하는 방법 을 고려하십시오 . Scala 2.7까지 테이블 형식은 다음과 같이 작성할 수 있습니다.

def tabulate[T](len: Int, f: Int => T) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

Scala 2.8에서는 런타임 정보가 올바른 표현을 생성하는 데 필요하기 때문에 더 이상 불가능합니다 Array[T]. ClassManifest[T]암시 적 매개 변수로 메소드 에를 전달하여이 정보를 제공해야합니다 .

def tabulate[T](len: Int, f: Int => T)(implicit m: ClassManifest[T]) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

속기 형식으로 컨텍스트 바인딩T대신 형식 매개 변수에 사용할 수 있습니다 .

def tabulate[T: ClassManifest](len: Int, f: Int => T) = {
    val xs = new Array[T](len)
    for (i <- 0 until len) xs(i) = f(i)
    xs
}

145

Robert의 답변은 Context Bounds의 기술적 세부 사항을 다룹니다. 그 의미에 대한 제 해석을 드릴게요.

Scala에서 View Bound ( A <% B)는 'can be seen as' <:의 개념을 캡처합니다 ( 상한값 은 'is a'의 개념을 캡처 함). 컨텍스트 바인딩 ( A : C)은 유형에 대해 'has a'라고 말합니다. " Thas a Manifest" 로 매니페스트에 대한 예제를 읽을 수 있습니다 . about Orderedvs에 링크 한 예 Ordering는 차이점을 보여줍니다. 방법

def example[T <% Ordered[T]](param: T)

매개 변수가 Ordered. 비교

def example[T : Ordering](param: T)

매개 변수에 Ordering.

사용 측면에서 규칙을 설정하는 데 시간이 걸리지 만 컨텍스트 경계가 뷰 경계보다 선호 됩니다 (이제 뷰 경계는 더 이상 사용되지 않음 ). 한 가지 제안은 직접 참조 할 필요없이 암시 적 정의를 한 범위에서 다른 범위로 전송해야 할 때 컨텍스트 바인딩이 선호된다는 것입니다 (이것은 확실히 ClassManifest배열을 만드는 데 사용되는 경우입니다 ).

뷰 경계와 컨텍스트 경계에 대해 생각하는 또 다른 방법은 첫 번째가 호출자의 범위에서 암시 적 변환을 전송한다는 것입니다. 두 번째는 호출자의 범위에서 암시 적 개체를 전송합니다.


2
"is a"또는 "seen as"가 아닌 "has a"가 저에게 중요한 통찰력이었습니다. 다른 설명에서는이 내용을 볼 수 없었습니다. 평범한 영어 버전의 약간 애매한 연산자 / 함수를 사용하면 훨씬 쉽게 흡수 할 수 있습니다. 감사합니다!
DNA

1
@Ben Lings .... 유형에 대한 'has a'는 무엇을 의미 합니까? 유형 은 무엇입니까 ?
jhegedus

1
@jhegedus 여기 내 구문 분석이 있습니다. "유형 정보"는 A가 유형을 참조한다는 것을 의미합니다. "has a"라는 문구는 객체 지향 설계에서 객체 관계를 설명하는 데 자주 사용됩니다 (예 : Customer "has an"Address). 그러나 여기서 "has a"관계는 객체가 아니라 유형 간의 관계입니다. "has a"관계가 OO 디자인에서와 같이 내재적이거나 보편적이지 않기 때문에 느슨한 비유입니다. 고객은 항상 주소를 가지고 있지만 컨텍스트 바인딩의 경우 A에는 항상 C가있는 것은 아닙니다. 컨텍스트 바인딩은 C [A]의 인스턴스가 암시 적으로 제공되어야 함을 지정합니다.
jbyler

저는 한 달 동안 스칼라를 배우고 있는데 이것이 제가 이번 달에 본 최고의 설명입니다! @Ben 감사합니다!
Lifu Huang

@Ben Lings : 감사합니다. 컨텍스트 바인딩이 무엇인지 이해하는 데 오랜 시간을 투자 한 후 귀하의 답변은 매우 도움이됩니다. [ has a나에게 더 의미가 있습니다]
Shankar

39

(이것은 괄호 안의 메모입니다. 먼저 다른 답변을 읽고 이해하십시오.)

컨텍스트 경계는 실제로 뷰 경계를 일반화합니다.

따라서이 코드는 View Bound로 표현됩니다.

scala> implicit def int2str(i: Int): String = i.toString
int2str: (i: Int)String

scala> def f1[T <% String](t: T) = 0
f1: [T](t: T)(implicit evidence$1: (T) => String)Int

이것은 또한 유형에서 유형 F으로의 함수를 나타내는 유형 별칭의 도움으로 Context Bound로 표현 될 수 있습니다 T.

scala> trait To[T] { type From[F] = F => T }           
defined trait To

scala> def f2[T : To[String]#From](t: T) = 0       
f2: [T](t: T)(implicit evidence$1: (T) => java.lang.String)Int

scala> f2(1)
res1: Int = 0

컨텍스트 바인딩은 유형 생성자와 함께 사용해야합니다 * => *. 그러나 유형 생성자 Function1는 종류 (*, *) => *입니다. 유형 별칭을 사용하면 두 번째 유형 매개 변수를 유형과 함께 부분적으로 적용 String하여 컨텍스트 바인딩으로 사용할 올바른 유형의 유형 생성자를 생성합니다.

트레이 트 내에서 타입 별칭을 사용하지 않고 Scala에서 부분적으로 적용된 타입을 직접 표현할 수 있도록하는 제안이 있습니다. 그런 다음 다음과 같이 작성할 수 있습니다.

def f3[T : [X](X => String)](t: T) = 0 

f2의 정의에서 #From의 의미를 설명해 주시겠습니까? F 형이 어디에서 만들어 지는지 잘 모르겠습니다 (정확하게 말했습니까?)
Collin

1
유형 프로젝션이라고하며 유형의 유형 멤버 From를 참조합니다 To[String]. 에 형식 인수를 제공하지 않으므로 형식이 아닌 From형식 생성자를 참조합니다. 이 유형 생성자는 컨텍스트 바인딩으로 사용하기에 적합한 종류 * -> *입니다. 이는 유형 T의 암시 적 매개 변수 를 요구 하여 유형 매개 변수를 제한합니다 To[String]#From[T]. 유형 별칭을 확장하면 Function1[String, T].
retronym

Function1 [T, String]이어야합니까?
ssanj

18

이것은 또 다른 괄호 안의 메모입니다.

벤 지적 , 바인딩 컨텍스트는 형식 매개 변수 및 유형 클래스 사이에 "이-는"제약 조건을 나타냅니다. 즉, 특정 유형 클래스의 암시 적 값이 존재한다는 제약 조건을 나타냅니다.

컨텍스트 바운드를 사용할 때 종종 암시 적 값을 표면화해야합니다. 예를 들어 제약 조건이 주어지면 제약 조건 을 충족하는 T : Ordering인스턴스가 종종 필요합니다 Ordering[T]. 여기설명 된대로implicitly 메서드 또는 약간 더 유용한 context메서드 를 사용하여 암시 적 값에 액세스 할 수 있습니다 .

def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) = 
   xs zip ys map { t => implicitly[Numeric[T]].times(t._1, t._2) }

또는

def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
   xs zip ys map { t => context[T]().times(t._1, t._2) }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.