【问题标题】:How does these Pascal Triangle functions work?这些帕斯卡三角函数是如何工作的?
【发布时间】:2013-03-06 15:32:41
【问题描述】:

我正在阅读Concepts, Techniques, and Models of Computer Programming,开头有一段代码,我怎么努力都看不懂。

declare Pascal AddList ShiftLeft ShiftRight

fun {Pascal N}
   if N==1 then [1]
   else
      L in
      L = {Pascal N-1} % Recursion
      {AddList {ShiftLeft  L}
               {ShiftRight L}}
   end
end

fun {ShiftLeft L}
   case L of H|T then
      H|{ShiftLeft T}  % Recursion
   else [0]
   end
end

fun {ShiftRight L}
   0 | L
end

fun {AddList L1 L2}
   case L1 of H1|T1 then
      case L2 of H2|T2
      then
     H1+H2|{AddList T1 T2} % Recursion
      end
   else nil
   end
end

我有点了解语言结构(这是对它的介绍),但真正阻碍我的是递归。

我试图在每个递归调用上打一个标签,抽象地说明这里发生了什么,但我就是想不通。

我要求的是对这些功能如何工作的清晰简单的解释。

【问题讨论】:

    标签: recursion oz mozart


    【解决方案1】:

    从 N == 1 开始:这很简单。结果就是[1]

    现在检查 N == 2:

    First we calculate L = {Pascal N-1} = {Pascal 2-1} = {Pascal 1} = [1]
    Now shifted to the left: [1 0]
    Shifted to the right: [0 1]
    AddList just adds elementwise. So the result for {Pascal 2} is [1 1].
    

    现在对于 N == 3:

    {Pascal 2} = [1 1]
    Shifted left:  [1 1 0]
    Shifted right: [0 1 1]
    Added:         [1 2 1]
    

    当然,该程序以相反的方式工作:它以一些更大的N 开始。但是在Pascal 函数的开头,程序会反复递归,直到参数N 变为1。像这样的:

    {Pascal 3}
       {Pascal 2}
          {Pascal 1}
          [1]
       [1 1]
    [1 2 1] 
    

    编辑:程序中实际上存在多种递归。 Pascal 中的第一个以某个整数 N 开头并向下递归到 1

    另一个(在辅助方法中)从一个由头和尾组成的列表开始,一旦列表为空就停止,即不能再拆分。 (这是使用所谓的 cons 列表,一种本质上递归的数据类型。)

    【讨论】:

      【解决方案2】:

      wmeyer 的解释非常好。我只想添加一个可能有用的“可视化”-->

      首先,我用的是书的原版(PDF),我相信,功能是这样的 -->

      declare Pascal AddList ShiftLeft ShiftRight
      fun {Pascal N}
         if N==1 then [1]
         else
            {AddList {ShiftLeft {Pascal N-1}} {ShiftRight {Pascal N-1}}}
         end
      end
      
      fun {ShiftLeft L}
         case L of H|T then
            H|{ShiftLeft T}
         else [0] end
      end
      
      fun {ShiftRight L} 0|L end
      
      fun {AddList L1 L2}
         case L1 of H1|T1 then
            case L2 of H2|T2 then
               H1+H2|{AddList T1 T2}
            end
         else nil end
      end
      

      假设您想查看帕斯卡三角形的第 8 行。你要输入:

      {Browse {Pascal 8}} 
      

      即您想显示将 8 输入到书中/此处定义的函数 Pascal 的结果。

      首先,函数测试它刚刚传递的值是否为 1(直到递归的最后一次迭代(或最终的递归调用)才会为真,此时 [1](来自如果 N==1) 将作为 THAT CALL OF Pascal 的输出返回,并将(Pascal 的)执行“链”传递回最先调用的下一个最近的调用(其中结果 [1] 被添加到匹配 ShiftLeft 或 ShiftRight 的结果,然后该结果被发送回链上,一直循环,直到到达第一个(Pascal 8)。所以调用深入 8 级,然后将答案向上传递这些级别,直到你得到最终答案......但我已经跳到前面了。

      好的,由于您输入了 8,因此测试 N==1 失败,因此不能立即移动“列表”并将它们添加到 else 子句中,函数无法做到这一点“方程式”中有未定义的术语说“我会尝试 N - 1!也许这将是最终答案!” (对于 ShiftLeft 和 ShiftRight - 所以每次递归发生时都会发生这种分支)

      因此,该函数在 ShiftLeft 和 ShiftRight 中等待来自 Pascal N-1 的答案...等待,等待...

      好吧,对于 N==1,{Pascal 7} 也不成立,因此 Pascal 的新调用(“调用”、第二和第三调用,左右!)也会问“什么是 Pascal N - 1"(这次是 7-1),他们都会等待答案......

      这样一直持续下去……哦等等,直到 N==1!

      然后 [1],一个列表,被返回 BACK UP THE CHAIN...所以,每个连续的等待函数调用,最近的第一个(记住所有这些在到达这里的路上越来越多地发生'bottom' 其中 N==1 随着拆分的增加(每次调用一次调用 ShiftLeft 和 ShiftRight))最终可以使用它一直在等待的答案进行 AddList 计算,从它自己的个人私人调用 ShiftLeft 和 ShiftRight .

      一切都一直到底部,分解成越来越多的函数调用,然后我们回到顶部,最后可以得到一个返回的答案。最后的答案是第一次调用 Pascal 函数 {Pascal 8} 的 else 子句,现在在内部(因为 Pascal 三角形的第 8 行是 [1 7 21 35 35 21 7 1])将如下所示:

      {AddList [1 7 21 35 35 21 7 0] [0 7 21 35 35 21 7 1]}

      添加后的列表作为最终答案返回并显示:[1 7 21 35 35 21 7 1]

      【讨论】:

        猜你喜欢
        • 2021-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-13
        • 2012-10-24
        • 1970-01-01
        相关资源
        最近更新 更多