Scheme - IF 对一个结果有几个操作

Scheme - IF w/ several operations for an outcome

我正在非常简要地研究 Scheme 并想知道是否有一种方法可以执行以下操作:向每个结果(#t 和 #f)添加几个操作。

(if (something)
    Do something //true, #t
    Do one thing AND another thing)) //false, #t

例如,给定一个采用整数 x 的已定义过程。如果大于五 --> 打印出一条消息。如果小于 5 --> 打印消息并将 x 设置为零:

(if (> x 5)
    "Greater than five"
    "Less than or equal to 5", (= x 0))

换句话说:我正在寻找一种允许我执行以下操作的机制(以 Java 语法表示):

if (cond) { //true
    //Do this
}
else { //false
    //Do this
    //AND this
}

边走边补!

好吧,你说我们真的卡住了,你至少知道 if 给你两个分支。

(if #t "a" "b") ; => "a"
(if #f "a" "b") ; => "b"

那么 "a""b" 可以是任何东西,对吧?如果它们是程序呢?

(define (a) "10")
(define (b) "20")
(if #t (a) (b)) ; => "10"
(if #f (a) (b)) ; => "20"

好的,我们知道过程主体可以按顺序计算任意数量的表达式。所以我们可以将 ab 扩展为

(define (a) (print "a is ") (print "10") (newline))
(define (b) (print "b is ") (print "20") (newline))
(if #t (a) (b)) ; "a is 10\n"
(if #f (a) (b)) ; "b is 20\n"

好的,所以每次你想要一个需要评估多个表达式的逻辑分支时定义一个过程可能有点麻烦,但至少它是有效的。然后,您可以使用 lambdas 内联过程,让您的生活更轻松

((if #t
     (λ ()
       (print "a")
       (print "b")
       (newline))
     (λ ()
       (print "c")
       (print "d")
       (newline)))) ; "ab\n"

((if #f
     (λ ()
       (print "a")
       (print "b")
       (newline))
     (λ ()
       (print "c")
       (print "d")
       (newline)))) ; "cd\n"

好吧,现在你真的不能再说你被困住了。事情看起来可能与 Java 中的情况不完全相同(谢天谢地),但至少事情的表现符合预期。

随着您继续学习语言和常用习语,您可能会偶然发现 cond and begin。它们可能会让您的生活更轻松,但您必须了解它们并没有什么神奇之处。您本可以自己轻松实现这些。

你可以随时一切。这也是我喜欢scheme/racket的原因之一。 holy/sacred 几乎什么都没有,你基本上可以实现任何你能想象到的东西。

事情是这样的,方案中的 if 与算法家族中的 if 有很大不同。 If在algol导数中是分支或条件跳转指令; if 直接改变了代码流。在 scheme/lisps 中,每个 if return 一个值。由于解释器或编译器的内部结构的限制,它不是一个完整的功能,但对于大多数目的,您可以将它视为另一个功能。

(if (something)
    Do something //true, #t
    Do one thing AND another thing)) //false, #t

错了,到底是怎么回事。

(if condition
  (return value of this first exp) //true value
  (return value or this second exp)) //false value

在方案中,当您希望函数有副作用时,即变异状态,您必须非常明确,最好用“!”标记变异状态的函数。在函数名称的末尾。

set!vector-set!之类的程序return一个未指定的值。如果你想要一个副作用和一个特定的值或特定序列中的多个副作用,你必须用 begin 把整个东西包起来。此外,如果您只是 (set! x 0),则您只是在本地范围内更改 x 的值,这可能不是您想做的。用于将 x 传递给函数的任何绑定符号仍然带有它的旧值。(set-car、vector-set!set-cell-contents! 会修改跨词法边界调用的数据结构的基础状态)显式递归或在闭包中隐藏一个值通常是合适的。

begin 的语法是 (begin exp1 ... expN)Begin 依次计算每个表达式,return 是最后一个表达式的值。唯一有用的是,如果最后一个表达式之前的所有表达式都产生副作用(变异状态或执行 I/O)。还要记住 definecond 的每个子句都包含和隐含 begin

在Java中打印字符串的程序会产生副作用。 If 与简单地 returning 字符串不同,这是 (if (> x 5) .. 的第一个分支正在做的事情。

所以为了简化事情,我们将保留字符串打印作为副作用,并将 x 的下一个或新值作为语句的 return 值。

(cond ((> x 5) (display "Greater than five")       (newline) x)
      (else    (display "Less than or equal to 5") (newline) 0))

或几乎等同的

(if  (> x 5) 
     (begin (display "Greater than five")       (newline) x)
     (begin (display "Less than or equal to 5") (newline) 0))

只需使用 begin,这与 λ 表达式非常相似:

(if #t
    (begin (displayln "Hello, world!") (displayln "wtf"))
    (displayln "stdio.h"))

您可以将任何您喜欢的东西包装到 begin 表达式中。它们通常用于流量控制,因为 begin 中的所有内容都会首先求值,但由于 if 是一个宏(使用 define-syntax 而不是 define 创建),它会处理 begin作为另一种表达方式。