5

我是 Scheme 的新手,如果条件为真,我试图让 if 语句执行多个操作。我试过类似的东西:

(if (char=? (string-ref str loc) #\a)
        ((+ count 1) (+ reference 1))
        ~else action, etc.~

它抱怨我的行为,说

申请:不是程序

如果我删除括号,那么真实条件的操作是:

(+ count 1) (+ reference 1)

它抱怨

如果:语法错误

并且根本无法运行。我错过了什么?

4

3 回答 3

12

代码有两个问题。第一,一个if形式在结果式和备选式中不能有多个表达式。两种可能的解决方案 - 您可以使用begin(不仅仅是一对括号,用于过程应用程序)来包围多个表达式:

(if (char=? (string-ref str loc) #\a)
    ; needs an explicit `begin` for more than one expression
    (begin
      (+ count 1)
      (+ reference 1))
    ; needs an explicit `begin` for more than one expression
    (begin
      ~else action, etc~))

...或使用 a cond,这是一个更好的选择,因为它已经包含一个隐含的begin

(cond ((char=? (string-ref str loc) #\a)
       ; already includes an implicit `begin`
       (+ count 1)
       (+ reference 1))
      (else
       ; already includes an implicit `begin`
        ~else action, etc~))

第二个问题更加微妙和严重,后续部分中的两个表达式可能都没有按照您的预期进行。这个:(+ count 1)什么都不做,增加的值丢失了,因为你在增加它之后没有使用它。与另一个相同:(+ reference 1),但至少这里的值是作为条件表达式的结果返回的。您应该将两个递增的值传递给一个过程(可能作为递归的一部分):

(cond ((char=? (string-ref str loc) #\a)
       ; let's say the procedure is called `loop`
       (loop (+ count 1) (+ reference 1)))
      (else
        ~else action, etc~))

或者直接在变量中更新增量的结果,尽管这不是在 Scheme 中编写解决方案的惯用方式(它看起来像 C、Java 等中的解决方案):

(cond ((char=? (string-ref str loc) #\a)
       ; here we are mutating in-place the value of the variables
       (set! count (+ count 1))
       (set! reference (+ reference 1)))
      (else
        ~else action, etc~))
于 2013-04-12T10:24:54.967 回答
0

您可以使用begin对一组表达式进行分组以逐个执行。

(if (char=? (string-ref str loc) #\a)
        (begin (+ count 1) (+ reference 1))
        ~else action, etc.~

begin只返回最后一个表达式的值,即(+ reference 1),所以(+ count 1)不使用 的值。

于 2013-04-12T05:59:02.120 回答
0

如果您尝试在 的一侧执行多个带有副作用的操作if,那么您需要将它们放入 中begin,如下所示:

(if (char=? (string-ref str loc) #\a)
    (begin (set! count (+ count 1))
           (set! reference (+ reference 1)))
    ~else action, etc.~

如果您不想改变变量,而是想一次返回两个值,那么您需要将表达式组合成一个对象,如下所示:

(if (char=? (string-ref str loc) #\a)
    (cons (+ count 1) (+ reference 1)))
    ~else expression~

在这种情况下,要提取计数和引用,您需要将carandcdr应用于if- 或者您实际上可以返回多个值,如下所示:

(if (char=? (string-ref str loc) #\a)
    (values (+ count 1) (+ reference 1)))
    ~else expression~

在这种情况下,要提取计数和引用,您需要在调用if. 一种方法是使用let-values,可能是这样的:

(define count&ref
  (λ (str ch)
    (let loop ([loc 0] [count 0] [reference 0])
      ; whatever other stuff you're doing
      (if (char=? (string-ref str loc) ch)
          (values (+ count 1) (+ reference 1)))
          ~else expression~ )))

(let-values ([(new-count new-ref) (count&ref "some stuff" #\u)])
  ;in here, new-count and new-ref are bound to whatever count&ref returned
  )

另一方面,如果countreference是您在循环中跟踪的变量,最简单的方法可能是在 中调用循环的下一次迭代if,如下所示:

(let loop ([loc 0] [count 0] [reference 0])
  ; whatever other stuff you're doing
  (if (char=? (string-ref str loc) #\a)
      (loop (+ loc 1) (+ count 1) (+ reference 1))
      ~else expression~ ))
于 2013-04-12T10:48:43.597 回答