如果if条件为真,如何运行多个表达式?

时间:2013-04-12 05:50:27

标签: if-statement scheme

我是Scheme的新手,如果条件为真,我试图让if语句执行多个动作。我试过像:

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

它抱怨我的行动,说

  

申请:不是程序

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

(+ count 1) (+ reference 1)

抱怨

  

if:bad syntax

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

3 个答案:

答案 0 :(得分:10)

代码有两个问题。第一种,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~))

...或使用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~))

答案 1 :(得分:0)

您可以使用begin将要执行的一组表达式分组。

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

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

答案 2 :(得分: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~

在这种情况下提取计数和引用,您需要将carcdr应用于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~ ))