通过递归调用来理解scala

时间:2017-01-04 18:57:56

标签: scala for-comprehension

我正在研究课程的最后一个项目" scala"中的函数式编程。我需要实现一个名为组合的函数,它接受一个字符出现列表并输出所有可能的字符出现子集。例如,出现列表List(('a', 2), ('b', 2))的子集是:

List(
  List(),
  List(('a', 1)),
  List(('a', 2)),
  List(('b', 1)),
  List(('a', 1), ('b', 1)),
  List(('a', 2), ('b', 1)),
  List(('b', 2)),
  List(('a', 1), ('b', 2)),
  List(('a', 2), ('b', 2))
)

我解决这个问题的方法是遍历每个字符(例如' a'),并获取其可能的出现次数(从0到2),并将其预备到当前子集。然后继续下一个字符并重复,直到我到达列表的末尾,这是由基本案例捕获的。我用以下的理解实现了这个:

type Occurrences = List[(Char, Int)]

def combinations(occurrences: Occurrences): List[Occurrences] =
  if (occurrences == List()) List() // base case
  else
    for {
      (c, n) <- occurrences
      subc <- combinations((occurrences.toMap - c).toList)
      i <- 0 to n
    } yield {
      if (i == 0) subc // not including c in the subset
      else (c, i) :: subc // including c in the subset
    }

当我拨打combinations(List(('a', 2), ('b', 2))时,此功能总是给我一个空列表。任何想法为什么会这样?

2 个答案:

答案 0 :(得分:1)

意外输出的原因在于:

subc <- combinations((occurrences.toMap - c).toList)

这将递归,加载堆栈帧,直到最终返回基本案例List()。现在,请记住,在for理解中,生成器(<-)是通过mapflatMap实现的,一旦您映射到空集合,您就完成了。< / p>

List[Int]().map(_ + 1).foreach(_ => println("got it"))  // no output

因此,未调用以下生成器i <- 0 to nyield没有任何内容,空List()是唯一返回的内容。然后堆栈框架弹出,接收到空的List()

答案 1 :(得分:0)

问题在于:

subc <- combinations((occurrences.toMap - c).toList)

在基本案例正上方的调用中,这被评估为List(),这会妨碍你的理解:

scala> for {a <- 0 to 3; b <- List()} yield a
res0: scala.collection.immutable.IndexedSeq[Int] = Vector()

这使得该调用返回List()等等,这意味着您将在调用堆栈中一直返回空列表,这就是您在顶部获得List()的原因。