List with type restrictions for sequential items

Is it possible to determine the type of list, where each pair of consecutive elements satisfies some relation (restriction). For example, a list of functions that can be linked:

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 
+6
source share
1 answer

It is generally not possible to describe interesting restrictions like this using a type alias. Instead, you need a type class that proves that the type has some property.

With Shapeless, you can often accomplish this using the type classes that the library provides, but I don't think this is the case. Fortunately, it's not too hard to write your own:

 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] {} 

What we are doing here is a description of how to create evidence inductively, as a base case - singleton HList . At each step, we use an element of type In to keep track of what type of output should be next (i.e., earlier in the list).

And to confirm that he is doing what we expect:

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

The first two work very well, and the third does not compile.

+5
source

Source: https://habr.com/ru/post/983277/


All Articles