我非常简要地研究了Scheme并想知道是否有办法执行以下操作:为每个结果添加几个操作(#t和#f)。
(if (something)
Do something //true, #t
Do one thing AND another thing)) //false, #t
作为一个例子,给定一个取整数x的定义过程。如果大于5 - >打印出一条消息。如果小于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
}
答案 0 :(得分:3)
随时随地补上!
好的,所以说你我们真的卡住了,你至少知道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"
好的,我们知道程序主体可以按顺序评估任意数量的表达式。因此,我们可以将a
和b
扩展为类似
(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和begin。它们可能会让你的生活更轻松,但你必须明白它们并不神奇。您可以自己轻松实现这些。
您可以随时制作所有内容。这是我喜欢计划/球拍的原因之一。没有什么是神圣/神圣的,你基本上可以实现你能想象的任何东西。
答案 1 :(得分:2)
这就是问题,方案中的if
与algol家族中的if
有很大的不同。 algol衍生物中的If
是分支或条件跳转指令; if
直接改变代码流。在scheme / lisps中,每个if
返回一个值。由于解释器或编译器的内部结构的限制,它不是一个完整的函数是lisps,但是对于大多数目的,你可以将它视为另一个函数。
(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!
之类的程序会返回未指定的值。如果您想要特定序列中的副作用和特定值或多个副作用,则必须使用begin
包装整个事件。此外,如果您只是(set! x 0)
,则只更改本地范围中的x值,这可能不是您想要做的。用于将x传递给函数的任何绑定符号仍然带有它的旧值。(set-car
,v ector-set!
和set-cell-contents!
确实修改了跨词法边界调用的数据结构的基础状态)显式递归或隐藏闭包中的值通常是合适的。
begin
的语法是(begin exp1 ... expN)
。 Begin
依次计算每个表达式,并返回最后一个表达式的值。唯一有用的是如果所有表达式在最后创建副作用之前(变异状态或执行I / O)。另请注意define
和cond
的每个子句都包含且隐式begin
。
在Java中,打印字符串的过程会产生副作用。如果不是简单地返回一个字符串,那就是(if (> x 5) ..
的第一个分支正在做的事情。
为简化起见,我们将字符串打印作为副作用,并将x的下一个或新值作为参数的返回值。
(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))
答案 2 :(得分:1)
只需使用begin
,这与λ
表达式非常相似:
(if #t
(begin (displayln "Hello, world!") (displayln "wtf"))
(displayln "stdio.h"))
您可以将任何您喜欢的内容包装到begin
表达式中。它们通常用于流控制,因为首先评估begin中的所有内容,但由于if
是一个宏(使用define-syntax
创建而不是define
),它会处理begin
作为另一种表达方式。