列出连续元素的类型约束

Tom*_*ula 6 scala shapeless

是否可以定义列表类型,其中每对连续元素满足某种关系(约束).例如,可以组成函数的函数列表:

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
Run Code Online (Sandbox Code Playgroud)

Tra*_*own 5

通常不可能使用类型别名来描述这样的有趣约束 - 相反,您需要一个类型类作为类型具有某些属性的证据.

使用Shapeless,通常可以使用库提供的类型类来完成此操作,但我不认为这是这种情况.幸运的是,写自己的并不难:

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] {}
Run Code Online (Sandbox Code Playgroud)

我们在这里所做的是描述如何以单身HList作为基本案例归纳地建立证据.在每一步,我们使用In类型成员来跟踪下一个(即列表中较早的)函数的输出类型必须是什么.

并确认它符合我们的预期:

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...
Run Code Online (Sandbox Code Playgroud)

前两个工作正常,而第三个不编译.