Scheme “cond”也是“let”吗?
通常,我发现我需要根据以前值的值有条件地计算一系列值。例如,让我们调用这些值Scheme “cond”也是“let”吗?,scheme,lisp,conditional-statements,let,Scheme,Lisp,Conditional Statements,Let,通常,我发现我需要根据以前值的值有条件地计算一系列值。例如,让我们调用这些值x,y和z。首先,我计算x。如果x满足某些条件,那么我计算y,这是x的函数,依此类推。示意图 ;; compute value x ;; if x =? #f -> #f ;; else compute value y = f(x) ;; if y =? #f -> #f ;; else compute value z = f(y) ;; et cetera 在这个计划中,你们是如何做到这一点的?我认为通常
x
,y
和z
。首先,我计算x
。如果x
满足某些条件,那么我计算y
,这是x
的函数,依此类推。示意图
;; compute value x
;; if x =? #f -> #f
;; else compute value y = f(x)
;; if y =? #f -> #f
;; else compute value z = f(y)
;; et cetera
在这个计划中,你们是如何做到这一点的?我认为通常会使用
cond
,但cond
会丢弃测试结果,因此在这种情况下没有任何用处。使用let*
,它在前面的绑定范围内按顺序评估初始化表单。在初始化表单中,使用和
使计算有条件
(let* ((x (compute-x))
(y (and x (f1 x)))
(z (and y (f2 y))))
;; code that uses the variables
)
您可以使用
cond
子句中的=>
设备,例如:
(define (testing p x)
(if (p x)
x
#f))
(display
(cond
((testing even? 1) => (lambda (x) ; the clause is skipped
(list 10 x)))
((testing even? 2) => (lambda (x) ; the clause is entered and
(list 20 x))))) ; `x` is bound to 2
您应该在相应的子句中嵌套cond
,以表示您描述的嵌套条件
这样,代码结构明显遵循您的逻辑,这总是很好的。因此,您的代码可以在标准的Common Lisp中这样编写:
(let ((it x-expression))
(if it
(let ((it (f it)))
(if it
it))))
注意,我没有给出else表单(可选),因为它在CL中是可选的。
Paul Graham以一种自动缓存测试值的方式引入
(defmacro aif (test-form then-form &optional else-form)
`(let ((it ,test-form))
(if it ,then-form ,else-form)))
(aif x-expression
(aif (f it)
(aif (f it)
it)
这在CL中效果很好,但在Scheme中会带来卫生问题。我知道有人为绑定名创建了一个额外的参数,但它失去了优雅性:
(aif x x-expression
(aif y (f x)
(aif z (f y)
z)))
在创建评估器时,我一直在试验cond
,我通常在剥离之前进行测试,最后是if
和let
嵌套。我的第一次迭代看起来像:
(定义(ev expr env)
(除秒)
((符号?表达式)(符号->值表达式环境))
((非(对?expr))expr=>(操作员(ev(汽车expr)环境)))
((宏?运算符)(宏应用表达式(cdr expr)env)=>(参数(映射(lambda(e)(ev e env))(cdr expr)))
(else(fun apply操作符args env)))
它还支持另一种方式,因为我发现重用=>并不是那么优雅:
(定义(ev expr env)
(除秒)
((符号?表达式)(符号->值表达式环境))
((非(对?expr))expr)
(定义运营商(ev(汽车出口)环境))
((宏?运算符)(宏应用表达式(cdr expr)环境))
(定义参数(map(lambda(e)(ev e env))(cdr expr)))
(else(fun apply操作符args env)))
现在,这也可以与aif
相同的方式使用。如果您感兴趣,Scheme宏是:
(定义语法defcond
(语法规则(else bind define=>)
((“构建”术语())
(条款)
((“构建”备选方案((绑定(BE)…rest))
(defcond“build”(让((b e)…备选)rest)
((u“build”备选方案((绑定名称(BE)…rest))
(defcond“build”(让name((b e)…可选)rest)
(uu“构建”备选方案((定义b e).rest))
(defcond“build”(letrec((b e))备选方案)rest))
((uu“build”替换((谓词-结果).rest))
(defcond“build”(if谓词-后续替换)rest)
((u“构建”备选方案((谓词结果=>(BE)…).rest))
(defcond“build”(如果谓词是后置的(let((b e)…)alternative))rest))
((uu“build”替换((谓词-结果).rest))
(defcond“build”(if谓词-后续替换)rest)
((uu“maybelse”((else表达式).rest))
(defcond“build”表达式rest))
((uu“maybelse”((某物表达)。休息))
(defcond“build”#f((某物表达式).rest)))
((“反向”术语())
(第二个“可能其他”术语)
((“反向”(第1术语…)
(第二个“反向”(第1个术语后…(术语…)
((uu)术语…)
(defcond“reverse”((术语…))))
不是很优雅的实现,但它可以工作。正如您所看到的,它支持bind
,也支持名为bind
。例如
(defcond
((不是(第1对))#f)
(绑定循环((lst lst)(acc 0)))
((空?lst)acc)
(其他(环路(cdr lst)(+acc(车辆lst)))
虽然我喜欢这个想法,但我仍然不认为它是一个神圣而优雅的想法。在更好的语法出现之前,我将为可读性编写它。例如:
(如果(不是(第1对))
#f
(让回路((一回路一回路)(附件0))
(如果(空?lst)
行政协调会
(环路(cdr lst)(+acc(车辆lst()()())))