2015-03-03 17 views
6

Czy można zdefiniować typ listy, w której każda para kolejnych elementów spełnia pewną zależność (ograniczenie). Na przykład lista funkcji takich, że funkcje mogą składać:Lista z ograniczeniami typu na kolejnych elementach

val f1: A => B = ??? 
val f2: B => C = ??? 
val f3: C => D = ??? 

type SafeList = ??? // how to define this? 

val fs: SafeList = f1 :: f2 :: f3 :: HNil // OK 

val fs: SafeList = f1 :: f3 :: HNil  // ERROR 

Odpowiedz

5

To nie jest zwykle możliwe do opisania interesujących ograniczeń jak to przy użyciu typu alias-zamiast chcesz klasę typu, która będzie służyć jako dowód, że type ma jakąś właściwość.

Z Shapeless często można tego dokonać przy użyciu klas klasowych dostarczanych przez bibliotekę, ale nie sądzę, że tak jest w tym przypadku. Na szczęście nie jest to zbyt trudne do napisania własnego:

import shapeless._ 

// Evidence that an hlist is made up of functions that can be composed. 
trait Composable[L <: HList] { 
    type In 
} 

object Composable { 
    type Aux[L <: HList, In0] = Composable[L] { type In = In0 } 

    implicit def composable0[A, B]: Aux[(A => B) :: HNil, A] = 
    new Composable[(A => B) :: HNil] { 
     type In = A 
    } 

    implicit def composable1[A, B, T <: HList] 
    (implicit tc: Aux[T, B]): Aux[(A => B) :: T, A] = 
     new Composable[(A => B) :: T] { 
     type In = A 
     } 
} 

def composable[L <: HList: Composable] {} 

Co robimy tutaj opisuje w jaki sposób zbudować dowody indukcyjnie, z Singleton HList jako przypadku bazowego. Na każdym kroku używamy członu typu In do śledzenia tego, jaki musi być wyjściowy typ następnej (tj. Wcześniej na liście) funkcji.

i potwierdzić, że robi to, czego się spodziewać:

scala> composable[(Int => String) :: (String => Char) :: HNil] 

scala> composable[(Int => Long) :: (Long => Char) :: (Char => String) :: HNil] 

scala> composable[(Int => String) :: (Symbol => Char) :: HNil] 
<console>:23: error: could not find implicit value for evidence parameter... 

pierwszych dwóch działać dobrze, natomiast trzeci nie kompiluje.

+0

Odpowiedz, która działa i jest edukacyjna. Dzięki! Co ciekawe, twój przykład działa nawet wtedy, gdy zamieniam ciała 'composable0' i' composable1' na 'null'. Będę jednak potrzebował instancji typu typeclass, kiedy spróbuję coś zrobić z listą, która wykorzystuje kompozycję, co, jak sądzę, będę musiał zrobić przy użyciu metod typeclass. –

+0

To prawda, w tym przypadku prawdopodobnie będziesz musiał dodać członka typu "Out", aby zrobić coś użytecznego poza dowodem na to, że typy są zgodne. –

Powiązane problemy