我指定的特质对我的模型:使用递归函数堆栈 - 在Scala中使用Free Monads Trampoline安全吗?
sealed trait TreeStructureModel{
val parentId: Option[Long]
val title: String
val id: Long
}
然后,我从记录从DB构建树:
trait SimpleTree[+TreeStructureModel]{
val title: String
val id: Long
}
trait Node[+TreeStructureModel] extends SimpleTree[TreeStructureModel]{
val inner: List[SimpleTree[TreeStructureModel]]
}
trait Leaf[+TreeStructureModel] extends SimpleTree[TreeStructureModel]
case class NodeImp[T <: TreeStructureModel](title: String, inner: List[SimpleTree[T]], id: Long) extends Node[T]
case class LeafImp[T <: TreeStructureModel](title: String, id: Long) extends Leaf[T]
object SimpleTree{
def apply[T <: TreeStructureModel](ls: List[T]): List[SimpleTree[T]] = {
def build(ls: List[T], current: T): SimpleTree[T] = {
val children = ls.filter{ v => v.parentId.isDefined && v.parentId.get == current.id}
if(children.isEmpty){
LeafImp(title = current.title, id = current.id)
} else {
val newLs = ls.filterNot{ v => v.parentId.isDefined && v.parentId.get == current.id}
NodeImp(title = current.title, id = current.id, inner = children.map{ch => build(newLs, ch)})
}
}
val roots = ls.filter{ v => v.parentId.isEmpty}
val others = ls.filterNot{ v => v.parentId.isEmpty}
roots.map(build(others, _))
}
}
此代码工作正常,但使用非尾递归调用。所以,我担心的是它会在大量记录中失败。我发现了一个非常好的article关于通过非尾递归使用Free monads Trampoline。 这看起来像要走的路,但我不能重写我的代码以使其堆栈安全。在本文的例子中,函数中只有一个递归调用,但在我的函数中可能会有很多,用于构建树。有人更有经验的自由monads可以帮助我吗?这甚至有可能吗?
列表的长度不是问题,但树的深度是。你可以改变'build'方法返回'Trampoline [SimpleTree]'而不是'children.map {ch => build(newLs,ch)}'使用'children.traverse {ch => build(newLs,ch) }',但你也可以直接以尾递归方式实现它,通过自下而上(从树叶)构建树。 –
你能显示更多细节吗?当将构建方法的结果更改为Trampoline [SimpleTree],然后children.traverse {ch => build(newLs,ch)}在构建时会出现类型不匹配错误(newLs,ch) – user2975535
请参阅我的答案。 –