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
冲突