2012-03-20 4 views
1

다음 코드는 유형 클래스를 정의합니다.타이프 스크립트 및 하위 유형

trait Foo[T] { 
    def toFoo(x: T): String 
} 

trait Foos { 
    def toFoo[T](f: T => String): Foo[T] = new Foo[T] { 
    def toFoo(x: T): String = f(x) 
    } 
} 

object Foo extends Foos { 
    def toFoo[A: Foo](a: A) = implicitly[Foo[A]].toFoo(a) 
    implicit def AToFoo: Foo[A] = toFoo { c => 
    "A" 
    } 
    implicit def BToFoo[T]: Foo[B] = toFoo { c => 
    "B" 
    } 

    implicit def ListToFoo[T: Foo]: Foo[List[T]] = toFoo { c => 
    c.map(toFoo(_)). 
    } 
} 

class A 
class B extends A 

지금 내가 toFoo(List(new A, new B)을 할 경우 내가 가지고있는 경우에 나는 List("A", "A") 대신 List("A", "B") 얻을. 유형 B 인 클래스의 경우 AToFoo 대신 BtoFoo 메소드가 사용되도록하려면 어떻게해야합니까?

+0

'List (new A, new B)'에 어떤 유형이 있습니까? –

+0

'List (A, new B)'타입이'List [A]' – Stephan

+0

이길 기대합니다.'List [A]'를 통해'toFoo'를 매핑하면 명백히'암시 적으로 [Foo [A]]'를 호출하고'AToFoo' 암시적인 def를 얻고 각 요소에이를 사용합니다. Typeclasses는 가치 지향적 인 파견을위한 것이 아니라 유형 지정 파견을 위해 설계되었으므로 하위 유형 지정과 항상 잘 작동하지는 않습니다. –

답변

2

암시 적 해석은 순전히 컴파일 타임 메커니즘입니다. 여기에있는 하위 유형을 쉽게 구분할 수있는 방법은 내재적으로 일치시키는 것입니다. 두 경우 모두 물론

implicit val AIsFoo : Foo[A] = toFoo { 
    case b: B => "B" 
    case a: A => "A" 
} 

으로 모두 BToFoo를 제거하고 대신 A 버전 거래를,이 계층의 일부가하는 방법에 위임 할 수있다. A에있는 메소드에 위임하고 B에 넘겨 줄 수 있으며 메소드를 추가 할 수없는 List의 typeclass 작업은 계속 수행 할 수 있습니다.

Foo은 반공 진이라고도 할 수 있습니다.

+0

패턴 일치를 사용하여 제안 사항을 구현했지만 아이 'X'에 직접'XIsFoo '를 쓸 수있는 대신'AIsFoo'에서'A'의 모든 자식을 확인해야하는 것은 너무 우아하지 않습니다. A. Foo'가 어떻게 작동하지 않을까요? 나는 시도했다 'trait Foo [-T] { def toFoo (x : T) : 문자열 }'' – Stephan