Scala,类型不匹配问题和类型推断问题

时间:2015-04-17 01:20:33

标签: scala shapeless

我有以下代码:

import shapeless._
trait TypeLike

case class Arg(name:String)

case class Predicate[Args <: HList, O <: TypeLike](name: String,args:Args,output:O,func: Args => O)(implicit val lubWitness: LUBConstraint[Args, Arg])

(这是来自Here的问题的结果) 我希望:

import scalax.collection.edge.LDiEdge
import scalax.collection.immutable.Graph
import scalax.collection.edge.Implicits._
import shapeless._

case class SimplePlan[A<:HList,B<:TypeLike,N<:Predicate[A,B]](plan:Graph[N,LDiEdge])

我在以下代码中遇到类型不匹配和推断类型参数错误:

object testMe extends App{
  val p1 = Predicate("Example1", Arg("test")::Arg("test")::HNil, new TypeLike {},
    (args: Arg ::Arg:: HNil) => { println(args(0));new TypeLike {} })


  val p2 = Predicate("Example2", Arg("test")::HNil, new TypeLike {},
    (args: Arg :: HNil) => { println(args(0));new TypeLike {} })

  val x = Graph((p1 ~+> p2)("booo"))
  val p = SimplePlan(x)
}

我必须添加什么才能解决问题? 如果你想拥有依赖项:

scalaVersion := "2.10.4"

libraryDependencies += "com.assembla.scala-incubator" %% "graph-core" % "1.9.1"

libraryDependencies += "com.chuusai" % "shapeless_2.10.4" % "2.1.0"

编辑:(更多解释)

谓词类是一个带有函数的类&#34; func&#34;这可以获得可变数量的参数。我使用前面提到的问题实现了这个(链接在那里) 我现在可以从Predicate实例化, p1 p2 。我有另一个班级&#34; SimplePlan&#34;它有一个图形的成员,我希望它的节点是一个谓词。但是因为我在谓词定义中使用了HList,所以每个 p1 p2 的类型都不同。我收到类型不匹配错误:

val p = SimplePlan(x)

我真的不知道,我应该如何定义SimplePlan来解决这个问题。确切的错误是:

Error: inferred type arguments [Nothing,Nothing,Planner.Predicate[_ >: shapeless.::[Planner.Arg,shapeless.HNil] with shapeless.::[Planner.Arg,shapeless.::[Planner.Arg,shapeless.HNil]] <: shapeless.::[Planner.Arg,shapeless.HList], Planner.TypeLike]] do not conform to method apply's type parameter bounds [A <: shapeless.HList,B <: Planner.TypeLike,N <: Planner.Predicate[A,B]]
  val p = SimplePlan(x)
          ^

Error: type mismatch;
 found   : scalax.collection.immutable.Graph[Planner.Predicate[_ >: shapeless.::[Planner.Arg,shapeless.HNil] with shapeless.::[Planner.Arg,shapeless.::[Planner.Arg,shapeless.HNil]] <: shapeless.::[Planner.Arg,shapeless.HList], Planner.TypeLike],scalax.collection.edge.LDiEdge]
 required: scalax.collection.immutable.Graph[N,scalax.collection.edge.LDiEdge]
  val p = SimplePlan(x)
                     ^

编辑2 (解释我想要的内容): 我需要这个用于我的研究项目,所以我想做的事情可能有点奇怪。我希望有一个谓词类,其中包含一个具有不同数字和类型参数的函数。我想要一个图表(这是我的执行图)。我可以摆脱HList的参数但我会丢失类型信息!

1 个答案:

答案 0 :(得分:1)

在处理无形时你遇到了一个常见的问题:每个HList都有不同的类型,并且在代码中没有丢失那些没有考虑到HLists概念的类型是非常棘手的。 / p>

你构建两个谓词,一个是Predicate [Arg :: Arg :: Nil,TypeLike],另一个是Predicate [Arg :: Nil,TypeLike]

Graph的定义如下:

trait Graph[N, E[X] <: EdgeLikeIn[X]]

请注意,Graph没有任何差异:它要求一个特定类型,并且您有两个不兼容的类型,因此无法编译。

如果你想知道为什么它们不兼容,请考虑一下:你的一个参数是一个函数,采用特定的HList形状,并返回一个TypeLike。它不需要任何HList。 HList的相同功能确保您在调用函数时必须匹配其形状,这使得无法一般性地讨论Predicates,就像常规集合一样,这正是Graph实际正在做的事情。

您可以通过稍微更改一下代码并明确表达几种类型来测试这种情况:

val x = Graph((p1 ~+> p1)("booo")) 
val p = SimplePlan[Arg::Arg::HNil,
          TypeLike,Predicate[Arg::Arg::HNil,TypeLike]](x)

如果我没有指定类型,它会失败:Scala类型推断有其局限性。它也不是你想要做的,因为你不希望你的所有谓词具有相同的形状。

我们可以通过在SimplePlan的定义中更具体一点来使类型推断工作。由于你只有一个谓词类型,N&lt;:谓词[A,B]并没有真正为你完成任何事情,所以我们可以编写

case class SimplePlan[A<:HList, B<:TypeLike](plan:Graph[Predicate[A,B],LDiEdge])

对于您的示例代码,它的作用相同。然后

val x = Graph((p1 ~+> p1)("booo"))
val p = SimplePlan(x)

直接编译,并在边缘从p1转到p2时提供更具描述性的错误。

解决问题的方法实际上取决于您尝试对此数据结构执行的操作。如果你正在尝试是恢复的确切类型,而反射你把一个谓语到图表后,我很伤心地说,我看不出这甚至有可能,因为图形不会让你的特定类型:图形是容器,并且不再能够将类型保持为常规列表。

你可以用一种擦除HList类型的方式包装谓词,然后将其放入图形中,但结果仍然会在它们进入SimplePlan之前删除它们。

也许如果您提供有关您尝试做的更多详情,我们可以帮助您更好?