例如,
我想检查一个元素是否在列表中。该算法很简单,让我们在C ++中做到这一点
bool element_of( const std::vector<int>& lst, int elem ) {
for( int i( 0 ), ie = lst.size(); i < ie; ++i )
if( elem == lst[i] )
return true;
return false;
}
由于Scheme不允许我使用单if
语句,我不能做类似上面的C ++代码。然后我想出了一个临时变量,即result
。 result
的初始值为#f
,接下来我递归调用函数来检查列表中的下一个项目,即cdr lst
...所以我的问题是,创建的变量是否为let
每次进入新的函数调用时还原其初始值,或者它的值在最后一次调用之前保持不变?
另一方面,使用fold
,我的解决方案是,
(define (element-of x lst)
(fold (lambda (elem result)
(if (eq? elem x) (or result #t) result))
#f
lst))
谢谢,
答案 0 :(得分:2)
每个Let
调用都会在Let
的主体正在评估的环境中创建一组新的变量。Let
语法是一个“语法糖”。 lambda通过传递给它的参数进行评估已经过评估。例如
(let ((a (func object))
(b (func object2)))
(cons a b))
与写作相同
((lambda (a b) (cons a b)) (func object) (func object2))
因此,您可以在Let
语法中看到,首先评估参数,然后评估正文,并在本地使用a
和b
的定义环境范围。因此,如果递归调用Let
,每次进入Let
调用的主体时,您正在新环境中评估主体(因为主体位于新定义的lambda内),并且定义在本地Let
范围中定义的参数将是不同的(它们实际上是由新lambda设置的嵌套环境中的新变量,而不仅仅是已经变异或“重新定义”的变量,就像您在一个C ++循环)。
另一种说法是,你的变量将类似于C ++递归函数中的局部范围变量...对于每个函数的堆栈帧,本地范围的变量将有自己的定义,以及它们自己的内存location ...它们不是像在循环中看到的变异变量,它在本地范围内重用相同的内存变量。
希望这有帮助,
杰森
答案 1 :(得分:1)
let
总是重新初始化变量;很明显,因为你必须始终提供新的绑定值。如,
(let ((a 42))
...)
在...
内,a
始终为42。它不会“保留”以前调用的值。
顺便说一句,我认为你打算写(or result (equal? elem x))
而不是(if (eq? elem x) (or result #t) result)
。 : - )
(or result (equal? elem x))
转换为以下C ++代码:
return result || elem == x;
(假设==
运算符已被重载以执行equal?
所执行的操作。)这样做的好处是,如果result
已经为真,则无需进一步比较进行。