静态类型的异构列表构建器

时间:2014-08-13 21:29:17

标签: scala types type-inference type-parameter heterogeneous

我想要实现的目标是:

  1. 定义异类列表的类型列表
  2. 从上面的定义中,构建一个静态类型的值列表
  3. 理想情况下,我想在IDE中键入以下表达式:

    val record = types.addValue("test").addValue(123).addValue(new java.util.Date())
    

    addValue()的参数类型限制为IDE类型推理引擎。

    以下是第1点工作实现:记录字段类型的规范:

    case class FieldType[V, T <: FieldType[_, _]](clazz: Class[V], tail: T) {
      def addValue(value: V) = FieldValue(value, tail)
    }
    case class FieldValue[V, T <: FieldType[_, _]](value: V, tail: T)
    object emptyFieldType extends FieldType(classOf[Null], null)
    

    这是由String, Int, Date

    组成的记录的示例规范
    val types = FieldType(
      classOf[String], FieldType(
        classOf[Int], FieldType(
          classOf[java.util.Date], emptyFieldType
        )
      )
    )
    

    通过使用addValue类型中的FieldType方法,编译器可以识别任何深度的参数类型:

    val a = types.addValue("") // here only String allowed
    val b = types.tail.addValue(23) // here only Int allowed
    val c = types.tail.tail.addValue(new java.util.Date()) // here only Date allowed
    

    可是...

    我还没有找到一种方法在FieldValue类型上实现转发方法,以实现一个流畅的界面,如我的第一个例子:

    val record = types.addValue("test").addValue(123).addValue(new java.util.Date())
    

    这是一个伪代码:

    case class FieldValue[V, T <: FieldType[_, _]](value: V, tail: T) {
      def addValue(x: What Here??) = tail.addValue(x) // not compiling!
    }
    

    我认为必须有可能,因为addValue的下一个参数的类型信息通过FieldValue成员tail包含在V中。但我找不到一种方法可以使这些信息可用于addValue方法,让编译器验证参数值的类型,以及IDE来建议正确的类型。

1 个答案:

答案 0 :(得分:5)

您可能需要查看shapeless

这是一个简单的例子,演示了如何静态指定异构列表的类型:

type R = String :: Int :: java.util.Date :: HNil

val record: R = "test" :: 123 :: new java.util.Date() :: HNil
// record: R = test :: 123 :: Thu Aug 14 00:21:52 CEST 2014 :: HNil

val record: R = "test" :: "foo" :: new java.util.Date() :: HNil
// error: type mismatch;
found   : shapeless.::[String,shapeless.::[String,shapeless.::[java.util.Date,shapeless.HNil]]]
required: R
  (which expands to)  shapeless.::[String,shapeless.::[Int,shapeless.::[java.util.Date,shapeless.HNil]]]
     val record: R = "test" :: "hola" :: new java.util.Date() :: HNil
                          ^

我不知道这是否已经满足您的需求,但无论如何您一定要检查无形的所有功能,因为它为这种通用编程提供了许多功能