【问题标题】:Scala, A type mismatch issue and type inference issueScala,类型不匹配问题和类型推断问题
【发布时间】:2015-04-17 01:20:32
【问题描述】:

我有以下代码:

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"

编辑:(更多解释)

谓词类是一个具有函数“func”的类,该函数可以获取可变数量的参数。我使用我之前提出的问题实现了这一点(链接在那里) 我现在可以从谓词 p1p2 实例化。我有另一个类“SimplePlan”,它有一个图的成员,我希望它的节点是一个谓词。但是因为我在 Predicate 定义中使用 HList,每个 p1p2 的类型是不同的。我收到类型不匹配错误:

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)
                     ^

Edit 2(解释我到底想要什么): 我的研究项目需要这个,所以我想做的可能有点奇怪。我想要一个谓词类,其中包含一个具有不同数量和类型参数的函数。我想要一个图(这是我的执行图)。我可以摆脱 HList 的参数,但我会丢失类型信息!

【问题讨论】:

  • 很难说你想在这里做什么。您能否将其最小化并提供实际的错误消息。
  • @TravisBrown 我添加了更多细节和错误。对不起,我真的不知道应该删除哪个部分才能更清楚,但我希望添加的部分能够澄清它。
  • here 和错误消息中可以看出,您正在获取Arg :: HNilArg :: Arg :: HNil 的LUB,这没有任何意义。 SimplePlan 你期望推断出什么 A
  • @TravisBrown 是 Arg:: HNil 和 'Arg::Arg::HNil` 都是 &lt;: HList 吗?我想要一个SimplePlan 的类型,它允许任何类型的Predicate?我什至不知道当我的班级成员中有一个 HList 时是否有可能
  • 是的,他们都是HLists,但是对于普通的HList,您几乎无能为力。

标签: scala shapeless


【解决方案1】:

在处理 shapeless 时,您会遇到一个常见问题:每个 HList 都有不同的类型,并且在代码中不丢失那些在其概念中没有考虑 HLists 的类型是非常棘手的。

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

Graph 的定义如下:

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

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

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

您可以通过稍微更改您的代码并明确几个类型来测试是否是这种情况:

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

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

我们可以通过在 SimplePlan 的定义中更具体一点来使类型推断起作用。由于您只有一种 Predicate 类型,因此 N <:predicate>

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 时提供更具描述性的错误。

解决问题的方法实际上取决于您尝试使用此数据结构做什么。如果您尝试在将 Predicate 放入 Graph 之后无需反射地恢复确切的类型,我很遗憾地说我看不到这是怎么可能的,因为 Graph 不会保留您的特定类型:Graph 是容器,并且不再能够像常规 List 那样保持类型。

您可以以擦除 HList 类型的方式包装谓词,然后将其放入图中,但结果仍然是在类型进入 SimplePlan 之前将其擦除。

也许如果您提供更多关于您尝试做什么的详细信息,我们可以为您提供更好的帮助?

【讨论】:

  • 感谢您的关注,我添加了另一个摘要,如果您有任何问题,请告诉我
  • 根据您所说的,在我看来您将不得不接受丢失类型信息,然后对图形执行使用反射。
  • 您使用反射的方式是什么?
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 2011-11-07
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 2016-04-04
  • 1970-01-01
相关资源
最近更新 更多