1-3 가지 문제를 해결합니다. 주요 응용 프로그램 중 하나는 HLists
arity를 추상화하는 것입니다. Arity는 일반적으로 특정 추상화 사용 사이트에서 정적으로 알려져 있지만 사이트마다 다릅니다. shapeless의 예 에서 이것을 취하십시오 .
def flatten[T <: Product, L <: HList](t : T)
(implicit hl : HListerAux[T, L], flatten : Flatten[L]) : flatten.Out =
flatten(hl(t))
val t1 = (1, ((2, 3), 4))
val f1 = flatten(t1) // Inferred type is Int :: Int :: Int :: Int :: HNil
val l1 = f1.toList // Inferred type is List[Int]
val t2 = (23, ((true, 2.0, "foo"), "bar"), (13, false))
val f2 = flatten(t2)
val t2b = f2.tupled
// Inferred type of t2b is (Int, Boolean, Double, String, String, Int, Boolean)
HLists
튜플 인수의 arity를 추상화하기 위해 (또는 이와 동등한 것)을 사용하지 않으면 flatten
이 두 가지 매우 다른 모양의 인수를 허용하고 형식이 안전한 방식으로 변환 할 수있는 단일 구현을 갖는 것이 불가능합니다.
고정 된 자족이 관여하는 모든 곳에서, 위와 같이, 방법 / 함수 매개 변수 목록과 사례 클래스를 포함하는, 튜플에 대해 추상화하는 능력은 관심이있을 것입니다. 타입 클래스 인스턴스를 거의 자동으로 얻기 위해 임의의 케이스 클래스의 특성을 추상화하는 방법에 대한 예제는 여기 를 참조 하십시오 .
// A pair of arbitrary case classes
case class Foo(i : Int, s : String)
case class Bar(b : Boolean, s : String, d : Double)
// Publish their `HListIso`'s
implicit def fooIso = Iso.hlist(Foo.apply _, Foo.unapply _)
implicit def barIso = Iso.hlist(Bar.apply _, Bar.unapply _)
// And now they're monoids ...
implicitly[Monoid[Foo]]
val f = Foo(13, "foo") |+| Foo(23, "bar")
assert(f == Foo(36, "foobar"))
implicitly[Monoid[Bar]]
val b = Bar(true, "foo", 1.0) |+| Bar(false, "bar", 3.0)
assert(b == Bar(true, "foobar", 4.0))
어떤 런타임 없습니다 반복은 여기에 있지만,이 중복 의 사용, HLists
(또는 이에 상응하는 구조)를 제거 할 수는. 물론 반복적 인 상용구에 대한 내성이 높으면 관심있는 각 모양마다 여러 가지 구현을 작성하여 동일한 결과를 얻을 수 있습니다.
세 번째 질문에서는 "... hlist에 매핑하는 함수 f가 너무 일반적인 것이 모든 요소를 받아 들일 수있는 경우 productIterator.map을 통해 사용하지 않는 이유는 무엇입니까?"입니다. HList를 통해 매핑하는 함수가 실제로 양식 Any => T
이면 매핑을 통해 productIterator
완벽하게 사용할 수 있습니다. 그러나 형식의 기능은 Any => T
일반적으로 그다지 흥미롭지 않습니다 (적어도 내부적으로 캐스트하지 않는 한 아닙니다). shapeless는 다형성 함수 값의 형태를 제공하여 컴파일러가 의심스러운 방식으로 유형별 사례를 선택할 수 있도록합니다. 예를 들어
// size is a function from values of arbitrary type to a 'size' which is
// defined via type specific cases
object size extends Poly1 {
implicit def default[T] = at[T](t => 1)
implicit def caseString = at[String](_.length)
implicit def caseList[T] = at[List[T]](_.length)
}
scala> val l = 23 :: "foo" :: List('a', 'b') :: true :: HNil
l: Int :: String :: List[Char] :: Boolean :: HNil =
23 :: foo :: List(a, b) :: true :: HNil
scala> (l map size).toList
res1: List[Int] = List(1, 3, 2, 1)
사용자 입력에 관한 질문 4와 관련하여 고려해야 할 두 가지 경우가 있습니다. 첫 번째는 알려진 정적 조건을 얻도록 보장하는 컨텍스트를 동적으로 설정할 수있는 상황입니다. 이러한 종류의 시나리오에서는 형태가없는 기술을 완벽하게 적용 할 수 있지만, 정적 조건 이 런타임에 얻어 지지 않으면 대체 경로를 따라야 한다는 점이 분명 합니다. 당연히, 이는 동적 조건에 민감한 방법이 선택적인 결과를 가져와야한다는 것을 의미합니다. 다음은 HList
s 를 사용하는 예입니다 .
trait Fruit
case class Apple() extends Fruit
case class Pear() extends Fruit
type FFFF = Fruit :: Fruit :: Fruit :: Fruit :: HNil
type APAP = Apple :: Pear :: Apple :: Pear :: HNil
val a : Apple = Apple()
val p : Pear = Pear()
val l = List(a, p, a, p) // Inferred type is List[Fruit]
의 유형은 l
목록의 길이 또는 요소의 정확한 유형을 캡처하지 않습니다. 그러나 특정 형식 (예 : 알려진 고정 스키마를 준수해야 함)을 예상 할 경우 해당 사실을 설정하고 그에 따라 조치를 취할 수 있습니다.
scala> import Traversables._
import Traversables._
scala> val apap = l.toHList[Apple :: Pear :: Apple :: Pear :: HNil]
res0: Option[Apple :: Pear :: Apple :: Pear :: HNil] =
Some(Apple() :: Pear() :: Apple() :: Pear() :: HNil)
scala> apap.map(_.tail.head)
res1: Option[Pear] = Some(Pear())
주어진 목록의 실제 길이가 다른 목록과 같은 길이라는 것을 제외하고는 다른 상황이 있습니다. 다시 말하지만, 이것은 완전히 정적으로 그리고 위에서와 같이 혼합 된 정적 / 동적 컨텍스트에서 형태없는 지원입니다. 여기를 참조 하십시오확장 된 예는 를 .
관찰 한 바와 같이, 이러한 모든 메커니즘은 최소한 조건부로 정적 유형 정보를 사용할 수 있어야하며 외부에서 제공되는 유형이 지정되지 않은 데이터에 의해 완전히 구동되는 완전히 동적 환경에서 이러한 기술을 사용할 수없는 것으로 보입니다. 그러나 2.10에서 스칼라 리플렉션의 구성 요소로 런타임 컴파일이 지원됨에 따라 이는 더 이상 극복 할 수없는 장애물이 아닙니다 ... 런타임 컴파일을 사용하여 가벼운 스테이징 형태를 제공하고 런타임에 정적 타이핑을 수행 할 수 있습니다 동적 데이터에 대한 응답 : 아래에서 발췌 한 내용 ... 전체 예제를 보려면 링크를 따르십시오.
val t1 : (Any, Any) = (23, "foo") // Specific element types erased
val t2 : (Any, Any) = (true, 2.0) // Specific element types erased
// Type class instances selected on static type at runtime!
val c1 = stagedConsumeTuple(t1) // Uses intString instance
assert(c1 == "23foo")
val c2 = stagedConsumeTuple(t2) // Uses booleanDouble instance
assert(c2 == "+2.0")
나는 의존적으로 유형이 지정된 프로그래밍 언어에 대한 그의 현명한 의견을 감안할 때 @PLT_Borat 가 그것에 대해 말할 것이 있다고 확신 합니다. ;-)