2013-06-27 5 views
6

저는 유형을 사용하여 엔티티 단위를 확인하는 경제적 모델을위한 작은 라이브러리에서 작업하고 있습니다. val apples = 2.0 대신 val apples = GoodsAmount[KG, Apples](2.0)이라고 적어주세요. 상품 묶음을 만들기 위해 무형의 라이브러리에서 HLists를 사용하려고했습니다. 이 잘 작동하지만 어떤 경우에는 내가 선호하는 일반 코드로 수 없습니다. 예 : 다음 문제.무형의 : 다형 함수의 유형 제약 검사

나는 엉망이 될 수있는 것을 설명하는 간단한 코드로 시작합니다. 우리는 Km을 나타내는 두 클래스와 다른 마일을 만듭니다. Km 클래스는 추가 할 수 있지만 마일은 추가 할 수 없습니다. 추상적 인 유형 T를 사용한다는 것은 주로 더 복잡한 라이브러리가되도록 동기 부여됩니다. 그리고 '+'함수에 대한 간접 호출은 무형의 경우에서 비슷한 것을 필요로하기 때문입니다.

trait Foo { 
    type T 
    val v: Double 
    def +[B <: Foo](other: B)(implicit ev: this.T =:= other.T) = v + other.v 
} 

trait _Km 
trait _Miles 

case class Km(v: Double) extends Foo { type T = _Km } 
case class Miles(v: Double) extends Foo { type T = _Miles } 

object ExampleSimple extends App { 
    def add[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: a.T =:= b.T) = { a + b } 

    add(Km(1), Km(2)) 
    // add(Km(1), Miles(2)) /* does not compile as intended */ 
} 

이것은 의도 한대로 작동합니다. 그러나 'Add'기능에 대한 Type Contraint 검사가 필요합니다. 경우, 첫 번째 오류를 수정해야

[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that a.T =:= b.T. 
[error]  implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a: Foo, b) => a + b } 
[error]                  ^
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:54: could not find implicit value for parameter mapper: shapeless.Mapper[ExampleShapeless.add.type,shapeless.::[(Km, Km),shapeless.::[(Km, Km),shapeless.HNil]]] 
[error] (l1 zip l2).map(add) 

: HLists이를 확장하는 나의 시도는 다음과 같습니다

object ExampleShapeless extends App { 
    import shapeless._ 

    val l1 = Km(1) :: Km(2) :: HNil 
    val l2 = Km(4) :: Km(3) :: HNil 

    object add extends Poly1 { 
    implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a, b) => a + b } 
    } 

    (l1 zip l2).map(add) 
} 

를하지만이 (스칼라 2.10.2을 사용하여) 다음과 같은 오류 메시지를 생성 caseTuple 함수에 유형 제약 조건을 추가 할 수는 있지만 솔직히 말해서 at 함수가 작동하는 방식과 암시 적 증거 매개 변수를 추가 할 수있는 위치를 이해하지 못했습니다. 또한 저는 매퍼가 암묵적인 가치를 발견 할 수 있도록하기 위해 무엇을해야하는지 모릅니다. 내가

implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b } 

으로 caseTuple 기능을 replase

덜 일반 버전은 잘 작동하지만 현재의 솔루션을 사용하는 것과 중복 코드를 많이 (좋아,이 솔루션은 여전히 ​​더 나은 것를 작성해야 튜플). 누군가이 문제를 해결할 수있는 힌트를 어떻게 줄 수 있습니까?

감사합니다, KLINKE

당신은 경우에 유형 매개 변수를 추가하여 일치하는 유형의 구성원을 필요로 할 수
+0

다음과 같이'Foo'를 정의 할 수 있습니다 :'trait Foo [T <: Foo] {v : Double; + (t T) : T = ...}'. '클래스 Km (val v : Double)은 Foo [Km]'을 확장합니다. 'implicit def add [T] = at [(Foo [T], Foo [T])] – senia

답변

7

:

object add extends Poly1 { 
    implicit def caseTuple[_T, A <: Foo { type T = _T }] = at[(A, A)] { 
    case (a, b) => a + b 
    } 
} 

또는 당신은 정말 걱정 때문에 당신은 실존 유형을 사용할 수 있습니다 그들은 동일합니다 :

object add extends Poly1 { 
    implicit def caseTuple[A <: Foo { type T = _T } forSome { type _T }] = 
    at[(A, A)] { 
     case (a, b) => a + b 
    } 
} 

두 가지 버전 모두 원하는 동작을 제공합니다.

+0

고마워, 이건 내 복잡한 경우에도 잘 작동한다 ;-)하지만 나는 여전히 누락 된 implicit 값에 문제가있다. 매퍼. 나는 그것을 스스로 풀려고 노력할 것이지만, 아마도 당신도 나를 도울 수 있습니까? – Klinke

+0

좋아요, 단순화 된 버전의 해결책을 찾았습니다. A에 대한 컨텍스트 바운드를 추가하면 도움이됩니다. 그래서 나는 이제''def caseTuple [_t, A <: Foo {type T = _T} <% Foo {type T = _T}] = ...'이번에는 풀 버전으로 쉽게 변환하지 못한다. ,하지만 잘하면 나는 새로운 문제를 해결할 수 있습니다. – Klinke

+0

@Klinke : 문제를 이해할 수 있을지 모르겠다. 'add'를 'ExampleShapeless'에 복사하여 붙여 넣으면 모든 것이 예상대로 작동하는 것 같습니다. –