2013-05-22 13 views
9

że mamy następujące klasy i jakieś wartości (Scala):Mapa na HList nie z podtypów typu rodzajowego w Scala & bezkształtne

class A[T](val x: T) 
class B[T](x: T, val y: T) extends A[T](x) 

val x1 = new A("test") 
val x2 = new B(1,2) 
val x3 = new B("foo","bar") 
val x4 = new A(1) 

Ponadto, możemy zdefiniować następujące wartości funkcji polimorficzny (używając bezkształtne) :

object f extends (A ~> Option) { 
    def apply[T](s: A[T]) = Some(s.x) 
} 

teraz możemy nazwać:

f(x1); f(x2); f(x3); f(x4) 

którym wszystkie sukces (i powinna IMHO). Jednakże:

val list = x1 :: x2 :: x3 :: x4 :: HNil 
list.map(f) 

// could not find implicit value for parameter mapper: 
// shapeless.Mapper[f.type,shapeless.::[A[String],shapeless.::[ 
// B[Int],shapeless.::[B[String],shapeless.::[A[Int],shapeless.HNil]]]]] 

Gdzie Spodziewałem:

Some("test") :: Some(1) :: Some("foo") :: Some(1) :: HNil 

Zauważ, że to działa:

val list2 = x1 :: x4 :: HNil // only instances of A 
list2.map(f) 

UPDATE

Wydaje się, że jeśli mamy określić każdy przypadek oddzielnie, w porządku:

object f extends Poly1 { 
    implicit def caseA[T] = at[A[T]]{s => Some(s.x)} 
    implicit def caseB[T] = at[B[T]]{s => Some(s.x)} 
} 

jednak próbuje wyrazić to nieco mądrzejszy, nie działa (nawet do prostych zastosowań):

object f extends Poly1 { 
    implicit def caseA[T, S <: A[T]] = at[S]{s => Some(s.x)} 
} 
+2

Nie mogę w tej chwili podać pełnej odpowiedzi, ale najprostszym rozwiązaniem jest użycie widoku związanego dla 'S' w Twojej ostatniej wersji' f' (tj. 'S <% A [T]') . Lub przynajmniej to powinno działać i nie wymaga dodawania przypadków dla każdego podtypu "A". –

+0

@TravisBrown Bardzo dziękuję za szybką odpowiedź. To rzeczywiście wydaje się działać. Naprawdę chciałbym wiedzieć dlaczego, jeśli masz prostą odpowiedź lub wskaźnik. W przeciwnym razie -> kopanie kodu – gzm0

Odpowiedz

9

Twoje najlepsze opcje są jednym użytkownika @ TravisBrown sugestii do wykorzystania widok oprawiony

object f extends Poly1 { 
    implicit def caseA[T, S <% A[T]] = at[S]{s => Some(s.x)} 
} 

lub bardziej lub mniej równoważnie ograniczenie typu

object f2 extends Poly1 { 
    implicit def caseA[S, T](implicit ev : S <:< A[T]) = at[S]{s => Some(s.x)} 
} 

lub wariacja na dwa rozwiązania sprawy, jakie czynniki na wspólność,

object f3 extends Poly1 { 
    def asub[T](s: A[T]) = Some(s.x) 
    implicit def caseA[T] = at[A[T]](asub) 
    implicit def caseB[T] = at[B[T]](asub) 
} 

Jest mało prawdopodobne, że polimorficzne wartości funkcji bezkształtne zostanie zmieniona bezpośrednio wspierać ten rodzaj argumentu typu wariancji potrzebnego do dokonania wstępnej pracy definition jak ty poszukiwane, ponieważ byłoby to sprzeczne z (wysoce pożądaną przez IMO) zdolnością do bardzo szczegółowego rozróżniania przypadków specyficznych dla określonego typu.

Powiązane problemy