使用模式匹配实现递归函数

时间:2014-05-01 13:38:25

标签: scala

我想使用模式匹配而不是if-else语句重写递归函数,但是我得到(正确的)警告消息,代码的某些部分是无法访问的。事实上,我的逻辑评估错误。

我想重写的功能是:

def pascal(c: Int, r: Int): Int =
  if (c == 0)
    1
  else if (c == r)
    1
  else
    pascal(c - 1, r - 1) + pascal(c, r - 1)

此功能按预期工作。我使用模式匹配重写它如下,但现在函数没有按预期工作:

def pascal2 (c : Int, r : Int) : Int = c match {
  case 0 => 1
  case r => 1
  case _ => pascal2(c - 1, r - 1) + pascal2(c, r - 1)
}

我哪里错了?

Main

println("Pascal's Triangle")
for (row <- 0 to 10) {
  for (col <- 0 to row)
    print(pascal(col, row) + " ")
  println()
}

2 个答案:

答案 0 :(得分:3)

以下陈述&#34;阴影&#34;变量r

case r =>

也就是说,&#34; r&#34;事实上,在这种情况下,声明并不是&#34; r&#34;你已经在上面定义了。它是自己的&#34; r&#34;等于&#34; c&#34;因为你告诉Scala将任何值分配给一个名为&#34; r。&#34;

的变量

因此,你真正想要的是:

def pascal2(c: Int, r: Int): Int = c match{
  case 0 => 1
  case _ if c == r => 1
  case _ => pascal2(c-1, r-1) + pascal2(c, r-1)
}

但这不是尾递归。

答案 1 :(得分:1)

我完全同意@wheaties并建议你遵循他的指示。为了完整起见,我想指出一些替代方案。

备选方案1

您可以自己编写unapply

def pascal(c: Int, r: Int): Int = { 
  object MatchesBoundary {
    def unapply(i: Int) = if (i==0 || i==r) Some(i) else None
  }
  c match {
    case MatchesBoundary(_) => 1
    case _ => pascal(c-1, r-1) + pascal(c, r-1)
  }
}

我不会声称它在这种情况下提高了可读性。只是想展示组合语义相似case s(具有相同/相似的案例主体)的可能性,这可能在更复杂的示例中有用。

备选方案2

还有一种可能的解决方案,它利用了Scala的模式匹配语法仅将小写变量视为匹配变量的事实。以下示例显示了我的意思:

def pascal(c: Int, r: Int): Int = { 
  val BoundaryL = 0
  val BoundaryR = r
  c match {
    case BoundaryL => 1
    case BoundaryR => 1
    case _ => pascal(c-1, r-1) + pascal(c, r-1)
  }
}

由于BoundaryLBoundaryR以大写字母开头,因此不会将它们视为变量,而是直接用作匹配对象。因此上述工作(将它们更改为boundaryLboundaryR时不会,这也会产生编译器警告)。这意味着您只需将r替换为R即可让您的示例正常工作。由于这是一个相当丑陋的解决方案,我只是出于教育目的而提及它。