我如何改进 Scala 中的这种广度优先搜索,使其更符合 FP 的习惯?

How can I improve this breadth-first search in Scala to make it more idomatic FP?

一直在寻找一种无需队列即可执行此操作并使其成为尾递归的方法。我在想 LazyLists 也可能有帮助。排队会更快吗?我基本上是通过与下一级子级的每个函数调用向下发送突变状态。

case class Tree [A] (
                      value : A,
                      Right: Option[Tree[A]],
                      Left: Option[Tree[A]]
                    )
object Tree {
  def liftChildren[A](t: Tree[A]) = {
    List(t.Left, t.Right).flatten
  }

  def findChild[A](value: A, t: Tree[A]) : Option[Tree[A]] = {
    var lvl = 0
      def searchChildren(t: List[Tree[A]]): (Option[Tree[A]], List[Tree[A]]) = {
        // could be removed, just for fun
        lvl += 1
        t.foreach(tt => println(s"Scanning Level ${lvl.toString} Value ${tt.value.toString}"))
        //
        val curfind = t.find(tt => {
          tt.value == value
        })
        curfind match {
          case Some(tr) => (Some(tr), t)
          case None => {
            val children: List[Tree[A]] = t.flatMap(tt => Tree.liftChildren(tt))
            children.isEmpty match {
              case true => (None, List.empty)
              case false => searchChildren(children)
            }
          }
        }
      }
    searchChildren(List(t))._1
    }
}

object main extends App {
  println("hello world")
  val tree = Tree[Int](
    1,
    Some(
      Tree[Int](2, None, Some(
        Tree[Int](5,None, Some(Tree[Int](6, None,None))))
      )
    ) ,
    Some(
      Tree[Int](
        3,
        Some(
          Tree[Int](4, None, Some(Tree[Int](7, None,None)))
        ), None
      )
    )
  )
  val res = Tree.findChild(6, tree)
  println("FoundIt" + res)
}

一切如我所愿。我只是想知道这是否会更好或更惯用的 FP。猫图书馆有帮​​助吗?

这是一个尾递归实现,使用模式匹配

final case class Tree[+A](value: A, left: Option[Tree[A]], right: Option[Tree[A]])

def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] = {
  import scala.collection.immutable.Queue

  @annotation.tailrec
  def bfs(queue: Queue[Tree[A]]): Option[Tree[A]] =
    queue.dequeueOption match {
      case None => None

      case Some((tree, remaining)) => tree match {
        case Tree(`value`, _, _) => Some(tree)
        case Tree(_, Some(left), Some(right)) => bfs(queue = remaining.enqueue(left).enqueue(right))
        case Tree(_, Some(left), None) => bfs(queue = remaining.enqueue(left))
        case Tree(_, None, Some(right)) => bfs(queue = remaining.enqueue(right))
        case Tree(_, None, None) => bfs(queue = remaining)
      }
    }

  bfs(queue = Queue(tree))
}

def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] = {
  @annotation.tailrec
  def dfs(stack: List[Tree[A]]): Option[Tree[A]] =
    stack match {
      case Nil => None

      case tree :: remaining => tree match {
        case Tree(`value`, _, _) => Some(tree)
        case Tree(_, Some(left), Some(right)) => dfs(stack = left :: right :: remaining)
        case Tree(_, Some(left), None) => dfs(stack = left :: remaining)
        case Tree(_, None, Some(right)) => dfs(stack = right :: remaining)
        case Tree(_, None, None) => dfs(stack = remaining)
      }
    }

  dfs(stack = List(tree))
}

这里有一些使用 LazyList.

的实现
final case class Tree[+A](value: A, children: List[Tree[A]])

// DFS by right.
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
  LazyList.unfold(List(tree)) {
    case Nil => None
     case tree :: remaining => Some((tree, tree.children reverse_::: remaining))
  }.find(tree => tree.value == value)

// DFS by left.
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
  LazyList.unfold(List(tree)) {
    case Nil => None
    case tree :: remaining => Some((tree, tree.children ::: remaining))
  }.find(tree => tree.value == value)

// BFS
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
  LazyList.unfold(Queue(tree)) { queue =>
    queue.dequeueOption.map {
      case (tree, remaining) => (tree, remaining.enqueueAll(tree.children))
    }
  }.find(tree => tree.value == value)