【问题标题】:Error: contract violation in Scheme错误:Scheme 中的合同违规
【发布时间】:2013-11-27 22:27:18
【问题描述】:

我在 Scheme 中练习递归。我下面的代码用于获取模式子句和语句,然后如果语句匹配模式则返回绑定列表,如果不匹配则返回 false:

(define remove-question-mark
  (lambda (s1)
    (if (memq #\? (string->list (symbol->string s1)))
        (cdr (string->list (symbol->string s1)))
        '())))

(define check-two-symbol
  (lambda (symbol1 symbol2)
    (if (and (regexp-match #rx#"\\?attrs" (symbol->string symbol1)) (list? symbol2))
        (cons symbol1 (list symbol2))
        (if (equal? symbol1 symbol2)
            '()
            (if (equal? (remove-question-mark symbol1) (string->list (symbol->string symbol2)))
                (cons symbol1 symbol2)
                #f)))))

(define clause
  (lambda (state1 state2)
    (if (and (null? (car state1)) (null? (car state2)))
        '() 
        (list (check-two-symbol (car state1) (car state2)) (clause (cdr state1) (cdr state2))))))

这是我的输入:

(clause '(wasDerivedFrom ?der ?e1 ?e2 . ?attrs_derv) '(wasDerivedFrom der e1 e2 (prov:type "Revision")))

我的代码出现了这个错误:

car: contract violation
  expected: pair?
  given: '()

预期输出:

((?der . der)
(?e1 . e1)
(?e2 . e2)
(?attrs_derv (prov:type "Revision")))

调试后发现(car state1)?attrs_derv时出错

如果我单独运行函数check-two-symbol,比如(check-two-symbol '?attrs-derv '(prov:type "Revision")),它会很好地打印出来:

(?attrs_derv (prov:type "Revision"))

但是使用 main 函数时,我得到了错误。那么有人可以帮我展示如何解决这个错误吗?我不太熟悉递归......

提前致谢!

【问题讨论】:

  • 查看Using scheme/racket to return specific items from a list,用户遇到相同的错误消息。
  • clause中,(and … (car (null? state2)))不应该是(and … (null? (car state2)))吗?
  • 应该是(and (null? state1) (null? state2))吧??
  • 我不知道 supposed 是什么让您的代码正常工作,但(car (null? ...)) 最终会导致错误(and 是短路的,所以你还没有看到它们)因为null? 返回#t#f 而你不能接受其中的car
  • 糟糕,(car (null?....)) 打错了。我真的很抱歉!

标签: recursion scheme


【解决方案1】:

错误消息表明您调用car 时使用的不是一对。你只在四个地方调用car,所以它是clause 中的一个。现在clause 仅被称为来自 clause,因此您不必走太远就能找到它。 clause 应该使用什么样的值来调用?当您递归调用clause(以下代码的最后一行)时,您将使用(cdr state1)(cdr state2) 调用它。有什么理由认为这些不是'()

(define clause
  (lambda (state1 state2)
    (if (and (null? (car state1)) (car (null? state2)))
        '() 
        (list (check-two-symbol (car state1) (car state2))
              (clause (cdr state1) (cdr state2))))))
                      ------------ ------------

让我们看看 clause 从您的初始输入中被调用:

(clause '(wasDerivedFrom ?der ?e1 ?e2 . ?attrs_derv) '(wasDerivedFrom der e1 e2 (prov:type "Revision")))
(clause '(?der ?e1 ?e2 . ?attrs_derv) '(der e1 e2 (prov:type "Revision")))
(clause '(?e1 ?e2 . ?attrs_derv) '(e1 e2 (prov:type "Revision")))
(clause '(?e2 . ?attrs_derv) '(e2 (prov:type "Revision")))
(clause '?attrs_derv '((prov:type "Revision")))

此时您将尝试在?attrs_derv 上调用car,这会导致错误,因为符号不是一对。事实上,如果我们将clause 简化为以下形式(这样它就不会调用check-two-symbol

(define clause
  (lambda (state1 state2)
    (if (and (null? (car state1)) (car (null? state2)))
        '() 
        (list (clause (cdr state1) (cdr state2))))))

然后尝试调用你提到的代码,我们得到一个错误:

> (clause '(wasDerivedFrom ?der ?e1 ?e2 . ?attrs_derv) '(wasDerivedFrom der e1 e2 (prov:type "Revision")))
car: contract violation
  expected: pair?
  given: '?attrs_derv

您遇到不同的错误这一事实意味着对 check-two-symbol 的调用在我们看不到的某个地方对 car 进行了调用,或者您向我们展示的测试与输出不一致你给我们看了。无论哪种情况,您似乎都在尝试并行递归两个列表。如果它们都是成对的,你只能这样做,所以你可能想要这样的代码

(if (not (and (pair? state1) (pair? state2)))
   <then-something>
   <else-something>)

【讨论】:

  • 我认为我不应该在 if 条件下调用 (car state1) 和 (car state2),因为当 if 语句返回 false 时已处理,我正确吗??
  • @TrungBún 不清楚您的代码应该做什么。 clause 不是一个特别有意义的名字,也没有 cmets。我们不能说什么会使它正确,因为我们不知道它应该做什么。也就是说,如果您要在各州调用 carcdr,您可能会检查它们是否满足 pair?
  • 我修好了它,我让它运行了!!!! :) 问题出在(car (null?....) 非常感谢您指出!!真的!!
猜你喜欢
  • 1970-01-01
  • 2019-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-26
  • 2015-11-14
  • 2013-08-10
  • 2016-10-13
相关资源
最近更新 更多