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.
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. –
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. –