我指定的特質對我的模型:使用遞歸函數堆棧 - 在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
請參閱我的答案。 –