【问题标题】:Tree depth: car/cdr contract violation树深度:汽车/cdr 合同违规
【发布时间】:2018-02-12 17:51:17
【问题描述】:

我正在使用球拍返回给定树的深度。这是当前代码:

(define (depth tree)
   (cond
      [(empty? tree) 0]
      [else
       (+ 1 (max (depth (cadr tree))
                 (depth (caddr tree))))]))

但我无法对其进行测试,因为我总是收到关于违反 car 和 cdr 合同的运行时错误。具体来说,当我尝试时

(depth '(1 2 3))

应该返回 1,我遇到:

length: contract violation
  expected: list?
  given: 2

无论我做什么,问题仍然存在,并且我不允许更改测试用例来解决问题。我敢肯定这很简单,但有人可以帮我理解吗?

(我看过其他帖子;有些帖子讨论了深度算法,但我特意询问的是此处介绍的汽车/cdr 合同违规问题。)

【问题讨论】:

    标签: tree lisp racket depth contract


    【解决方案1】:

    您的问题的答案包含在您的基本案例中:empty?'() 是什么?这是list 的结尾。因此,如果您想知道深度,您需要确保在相关列表内的任何 列表 上重复。

    当我阅读代码时,您要问的是:如果tree 有某个元素,则取该元素的深度与下一个元素的深度相比的最大值。您可能想问的是,用 列表其余部分的深度取该元素的最大深度(这不是caddr,而是cdr)。所以我假设您希望将2 的深度设为零(它不是列表)。如果是这样,您是否在cond 测试中正确列出了这种情况?唔。也许有一种方法可以检查某物是否是一对,在这种情况下我们会重复,否则它的深度为 0...

    【讨论】:

      【解决方案2】:

      这里可能存在几个问题。

      首先也是最重要的:您粘贴的错误与“长度”有关,但在您的程序中没有使用“长度”。当我运行您的代码时,出现以下错误:

      cadr: contract violation
        expected: (cons/c any/c pair?)
        given: 2
      

      了解这里发生的事情的最佳方法可能是使用步进器。更具体地说:将语言级别设置为“Beginning Student with List Abbreviations”,将以下程序放在定义窗口中,然后单击“步骤”:

      (define (depth tree)
         (cond
            [(empty? tree) 0]
            [else
             (+ 1 (max (depth (cadr tree))
                       (depth (caddr tree))))]))
      
      (depth '(1 2 3))
      

      【讨论】:

        【解决方案3】:

        简答:

        使用pair? 代替empty? 并切换子句。给你:

        (define (depth tree)
           (cond
              [(pair? tree)
               (+ 1 (max (depth (cadr tree))
                         (depth (caddr tree))))]
              [else 0]))
        

        长答案

        问题在于您使用了cadrcaddr,正如您在运行给定示例时所看到的那样:

        实际错误是:

        cadr: contract violation
          expected: (cons/c any/c pair?)
          given: 2
        

        这是因为您只检查empty?,它仅在给定一个空列表时才返回#t。像2 这样的数字 NOT 是一个空列表,因此它返回 #f,然后它会转到第二种情况,您尝试获取空列表的 cadr。显然这会失败。

        检查某个东西是否为pair? 可以得到你想要的实际情况。

        一般来说,您最好退后一步,真正考虑一下您正在遍历的数据类型。

        例如,我可以写出:

        Tree = (Cons LeftNode RightNode)
             | Number
        

        考虑到这一点,更容易看到carcdr 将直接访问您的孩子。

        (car (Cons LeftNode RightNode)) => LeftNode
        
        (cdr (Cons LeftNode RightNode)) => RightNode
        

        显然carcdr 的数字将是一个错误。

        从这里很明显如何定义你的深度函数

        (define (depth tree)
           (cond
              [(pair? tree)
               (+ 1 (max (depth (car tree))
                         (depth (cdr tree))))]
              [else 0]))
        

        请注意,我使用了pair? 而不是empty?。如果您真的想了解这里发生了什么,我强烈建议您查看How To Design Programs,它会以更慢(且更简洁)的方式引导您完成我在这里使用的设计配方步骤。

        如果您愿意,您甚至可以将此想法扩展为包含具有 3 或 4 个子节点的树:

        Tree = (Listof Tree Tree Tree)
             | (Listof Tree Tree Tree Tree)
             | Number
        

        鉴于此,您能找出具有任意数量子树节点的树的粗略数据类型吗?

        【讨论】:

          猜你喜欢
          • 2018-01-12
          • 1970-01-01
          • 2021-12-21
          • 2012-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-17
          • 1970-01-01
          相关资源
          最近更新 更多