错误:方案中存在违反合同的情况



我正在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 '?attrs-derv '(prov:type "Revision"))一样单独运行函数check-two-symbol,它会很好地打印出来:

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

但是对于主函数,我会出错。那么,有人能帮我展示如何修复这个错误吗??我对递归不是很熟悉。。。。

提前感谢!

错误消息指示您正在使用非配对的东西调用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>)

最新更新