我是Scheme的新手,如果条件为真,我试图让if语句执行多个动作。我试过像:
(if (char=? (string-ref str loc) #\a)
((+ count 1) (+ reference 1))
~else action, etc.~
它抱怨我的行动,说
申请:不是程序
如果我删除括号,那么对于真实条件的操作是:
(+ count 1) (+ reference 1)
抱怨
if:bad syntax
并且根本无法运行。我错过了什么?
答案 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~
在这种情况下提取计数和引用,您需要将car
和cdr
应用于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
)
另一方面,如果count
和reference
是您在循环中跟踪的变量,最简单的方法可能是调用循环的下一次迭代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~ ))