Scala:递归隐式类型

Scala:递归隐式类型,scala,scala-implicits,Scala,Scala Implicits,我有以下解析特性,可以为对象的开始和结束提供文件位置: case class FilePosn(lineNum :Int, tabs: Int, spaces: Int, fileName: String) {/*code omitted*/} trait PosnEnds { def startPosn: FilePosn def endPosn: FilePosn def multiLine: Boolean = startPosn.lineNum != endPosn.lin

我有以下解析特性,可以为对象的开始和结束提供文件位置:

case class FilePosn(lineNum :Int, tabs: Int, spaces: Int, fileName: String)
{/*code omitted*/}

trait PosnEnds
{
  def startPosn: FilePosn
  def endPosn: FilePosn
  def multiLine: Boolean = startPosn.lineNum != endPosn.lineNum
  def OneLine: Boolean = startPosn.lineNum == endPosn.lineNum
  def indent: Int = startPosn.tabs
  def startLine: Int = startPosn.lineNum
  def endLine: Int = endPosn.lineNum
}

object FilePosnVoid extends FilePosn(0, 0, 0, "There is no File position")
{ override def posnString(indentSize: Int): String = "No File Posn: " }
在同伴对象中,我创建了一个隐式,因此posnend序列本身就是隐式posnend:

object PosnEnds
{
  implicit class ImpPosnEndsSeq[A <: PosnEnds](thisSeq: Seq[A]) extends PosnEnds
  {
    override def startPosn: FilePosn = thisSeq.fHead(FilePosnVoid, (h, t) => h.startPosn)
    override def endPosn: FilePosn = thisSeq.fLast(FilePosnVoid, _.endPosn)     
  }
}
对象PosnEnds
{
隐式类ImpPosnEndsSeq[A h.startPosn)
override def endPosn:FilePosn=thiseq.fLast(FilePosnVoid,u.endPosn)
}
}
是否有任何方法可以隐式递归使用它,因此Seq[Seq[a]]和Seq[Seq[a]]等将隐式转换为PosnEnds特征?在实践中,我可能不需要很大的深度,但最好使用一个优雅的解决方案,隐式转换任意深度的Seq

目前,对于深度2,我正在使用:

implicit class ImpPosnEndsSeqSeq[A <: PosnEnds](thisSeq: Seq[Seq[A]]) extends PosnEnds
{
  override def startPosn: FilePosn = thisSeq.fHead(FilePosnVoid, (h, t) => h.startPosn)
  override def endPosn: FilePosn = thisSeq.fLast(FilePosnVoid, _.endPosn)     
}
隐式类ImpPosnEndsSeqSeq[A h.startPosn)
override def endPosn:FilePosn=thiseq.fLast(FilePosnVoid,u.endPosn)
}

是的。您可以使用typeclass mediator来完成

我允许自己对你的例子做一些小的修改,使它更具可复制性

val void = new FilePosn(0, 0, 0, "There is no File position") {
  override def posnString(indentSize: Int): String = "No File Posn: "
}

def empty = new PosnEnds {
  def startPosn: FilePosn = void
  def endPosn: FilePosn = void
}
您首先需要的是一些简单的类型类,比如

trait MakePosnEnds[X] extends (X => PosnEnds)
现在,您可以为归纳引入规范元素:

implicit object idMakePosnEnds extends MakePosnEnds[PosnEnds] {
  def apply(x: PosnEnds) = x
}

implicit def seqMakePosnEnds[X](implicit recur: MakePosnEnds[X]) = new MakePosnEnds[Seq[X]] {
  def apply(x: Seq[X]): PosnEnds = new PosnEnds {
    val thisSeq = x.map(recur)
    override def startPosn: FilePosn = thisSeq.headOption.fold(void)(_.startPosn)
    override def endPosn: FilePosn = thisSeq.lastOption.fold(void)(_.endPosn)
  }
}
最后,您可以定义隐式转换

implicit def toPosnEnds[X](x: X)(implicit make: MakePosnEnds[X]): PosnEnds = make(x)
从此

Seq(Seq(Seq(empty))).startLine
编译并成功运行

与您尝试的主要区别:我们不等待隐式转换到堆栈。隐式解析可以是递归的,但隐式转换不能

所以我们使用的是一些无值类型,即仅使用隐式参数即可实现的类型,这意味着可以由编译器构造。
然后才将此逻辑投影到具体值。

是的。您可以使用typeclass mediator进行此操作

我允许自己对你的例子做一些小的修改,使它更具可复制性

val void = new FilePosn(0, 0, 0, "There is no File position") {
  override def posnString(indentSize: Int): String = "No File Posn: "
}

def empty = new PosnEnds {
  def startPosn: FilePosn = void
  def endPosn: FilePosn = void
}
您首先需要的是一些简单的类型类,比如

trait MakePosnEnds[X] extends (X => PosnEnds)
现在,您可以为归纳引入规范元素:

implicit object idMakePosnEnds extends MakePosnEnds[PosnEnds] {
  def apply(x: PosnEnds) = x
}

implicit def seqMakePosnEnds[X](implicit recur: MakePosnEnds[X]) = new MakePosnEnds[Seq[X]] {
  def apply(x: Seq[X]): PosnEnds = new PosnEnds {
    val thisSeq = x.map(recur)
    override def startPosn: FilePosn = thisSeq.headOption.fold(void)(_.startPosn)
    override def endPosn: FilePosn = thisSeq.lastOption.fold(void)(_.endPosn)
  }
}
最后,您可以定义隐式转换

implicit def toPosnEnds[X](x: X)(implicit make: MakePosnEnds[X]): PosnEnds = make(x)
从此

Seq(Seq(Seq(empty))).startLine
编译并成功运行

与您尝试的主要区别:我们不等待隐式转换到堆栈。隐式解析可以是递归的,但隐式转换不能

所以我们使用的是一些无值类型,即仅使用隐式参数即可实现的类型,这意味着可以由编译器构造。
然后才将这个逻辑投射到具体的值。

对于
A
执行的两种情况,您是否期望
trait PosnEnds
的操作?对于
A
执行的两种情况,您是否期望
trait PosnEnds
的操作?使用您的代码,即使使用在use文件中导入。@RichOliver这很糟糕。尝试将它们全部放入一些
对象隐式
,然后
导入隐式。
。还要注意,如果旧的
隐式类ImpPosnEndsSeq
在目标源代码中仍然可见,它可能与
def toPosnEnds
冲突,我似乎无法获取隐式要使用您的代码,即使在使用文件中使用导入,这也很糟糕。@RichOliver。尝试将它们全部放在一些
对象隐式
中,然后
导入隐式。
。还要注意,如果旧的
隐式类ImpPosnEndsSeq
在目标源代码中仍然可见,则可能与
def ToposEnds
冲突