【问题标题】:Scheme ill-formed special formScheme 格式不正确的特殊形式
【发布时间】:2012-01-26 22:41:48
【问题描述】:

我对 Scheme 很陌生,当我尝试使用此功能时,我收到“格式错误的特殊形式”错误。如果 original 的长度为 0,我希望函数返回 left。否则,我希望它执行追加调用和递归调用。我想我可能做了一些非常愚蠢的事情导致了这种情况。有什么帮助吗?

(define (partition left right original)
(if (= (length original) 0) left
    (append left (car original))
        (append right (car (reverse original)))
              (partition left right (reverse original))))

【问题讨论】:

    标签: scheme


    【解决方案1】:

    在我开始之前,请尝试indent your programs properly。在这种情况下,它会使错误更加明显。

    您遇到了许多来自其他语言的 Scheme 新手遇到的减速带:

    Lisp 中的if(包括方案)实际上是三元运算符,而不是类 C 世界中的 if 块。

    您的代码试图以三种以上的形式呈现if,因此它失败了。天真地,您可以做的是使用块构造 begin(Common Lisp 中的 progn)来确保条件的单个分支仅包含单个表单。

    (define (partition left right original)
      (if (= (length original) 0)
          left
          (begin 
            (append left (car original))
            (append right (car (reverse original)))
            (partition left right (reverse original))))) 
    

    现在,我感觉这也不会满足您的要求,因为append 是函数式的(也就是说,它返回结果而不修改其参数)。换句话说,你对append 的调用都不会做任何事情,original 永远不会变短。你在这里真正想要的是类似

    (define (partition left right original)
      (if (= (length original) 0)
          left
          (partition (cons (car original) left)
                     (cons (last original) right)
                     (cdr (take original (- (length original) 1))))))
    

    【讨论】:

    • 顺便说一下,您可能想研究一个提供良好错误消息的 Scheme 实现。例如,在 Racket 中,它会为您的原始代码提供以下错误消息:“if: bad syntax (has 5 parts after keyword) in ...”
    • “正确缩进”的链接不再可用。你有什么新的链接可以参考吗?
    【解决方案2】:

    if 表单由 4 部分组成:

    1. if这个词。
    2. 条件。
    3. 当时的分支。
    4. else 分支。

    您的if-form 包含 6 个部分。 (= (length original) 0) 是条件。 left 是 then 分支,(append left (car original)) 是 else 分支。但是另外两个应该是什么?对读者来说很明显,它们仍然应该是 else 分支的一部分,但编译器不知道这一点。就编译器所知,您可能还打算让 left(append left ...) 进入 then 分支,而让其他两个进入 else 分支。

    如果您想在if 中执行多个表达式,您需要某种方法将属于同一分支的表达式组合在一起。你可以像这样使用begin

    (if condition
      (begin
        (do-something-in-the-then-branch)
        (do-something-else-in-the-then-branch))
      (begin
        (do-something-in-the-else-branch)
        (do-something-else-in-the-else-branch)))
    

    但是,在您的情况下,这实际上并没有帮助,因为 append 不能就地工作。 IE。如果你这样做(append left (car original))left 的值实际上不会改变。相反,append 将返回一个包含left(car original) 内容的新列表,而不会实际更改其中任何一个列表。所以要使用append的结果,你需要使用它的返回值。

    因此,为了使您的函数正常工作,您应该将调用 append 直接作为参数传递给 partition,或者使用 let 将结果分配给变量并将变量传递给 partition

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 2011-08-02
      • 2018-08-25
      • 2013-06-06
      • 1970-01-01
      • 2016-02-01
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多