繁体   English   中英

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

[英]Scala, A type mismatch issue and type inference issue

我有以下代码:

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

(这是来自这里的一个问题的结果),我想拥有:

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

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

在处理无形状时,您经常遇到一个问题:每个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的定义中更具体一些来使类型推断起作用。 由于您只有一个谓词类型,因此N <:Predicate [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时提供更具描述性的错误。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM