【发布时间】:2017-07-17 17:01:19
【问题描述】:
我已经为我的模型指定了特征:
sealed trait TreeStructureModel{
val parentId: Option[Long]
val title: String
val id: Long
}
然后我从数据库中的记录构建一棵树:
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。 这看起来像是一种方法,但我无法重写我的代码以使其堆栈安全。在文章中的示例中,函数中只有一个递归调用,但在我的函数中可以有很多,用于构建一棵树。对 Free monads 更有经验的人可以帮我解决这个问题吗?这甚至可能吗?
【问题讨论】:
-
列表的长度不是问题,但树的深度是。您可以将
build方法更改为返回Trampoline[SimpleTree],而不是children.map{ch => build(newLs, ch)}使用children.traverse{ch => build(newLs, ch)},但您也可以通过自下而上(从叶子)构建树来直接递归实现它。跨度> -
你能提供更多细节吗?当将 build 方法的结果更改为 Trampoline[SimpleTree] 时,children.traverse{ ch => build(newLs, ch)} 在 build(newLs, ch) 上出现类型不匹配错误
-
见我的回答。
标签: scala recursion scalaz scala-cats