球拍让一些疑惑

时间:2014-04-01 23:34:59

标签: racket

(let ((+ *)
      (* +))
  (+ 3 (* 4 5)))

输出:27

(let ((+ *))
  (+ 3 (* 4 5)))

输出:60

我不明白let是如何运作的。任何人都可以帮助我吗?

4 个答案:

答案 0 :(得分:2)

可让

let绑定在 parallel 中,因为

(let ((+ *) (* +))
  (+ 3 (* 4 5)))

实际上扩展为

((lambda (+ *) 
   (+ 3 (* 4 5))) 
 * +)

所以Scheme通常会这样做:

  1. 参数*+会根据某些序列
  2. 中的各自值(过程*+)进行评估>
  3. 然后绑定到形式参数+*(这也发生在一些序列中,但在两种情况下都无关紧要)
  4. 然后将内部函数的主体评估为(* 3 (+ 4 5))
  5. 只需添加printf即可确认:

    (let ((+ *) (* +))
      (printf "+ is ~a and * is ~a \n" + *)
      (+ 3 (* 4 5)))
    
    => 
    + is #<procedure:*> and * is #<procedure:+> 
    27
    

    可让*

    如果您希望绑定发生在序列中,那么您必须使用 let *,因为

    (let* ((+ *) (* +))
      (+ 3 (* 4 5)))
    

    扩展为

    ((lambda (+) 
       ((lambda (*) 
          (+ 3 (* 4 5))) 
        +))
     *)
    

    所以

    1. *绑定到+
    2. 然后+已绑定到*,再次绑定到*,这实际上没有效果
    3. 然后表达式变为(* 3 (* 4 5))
    4. 并且因为第二个绑定没有效果,所以这相当于简单地

      (let ((+ *))
        (+ 3 (* 4 5)))
      

答案 1 :(得分:1)

在第一个表达式中,*绑定到+的原始值,+绑定到*的原始值。因此(+ 3 (* 4 5))与原始绑定相当于(* 3 (+ 4 5))。这与中缀表达式3 * (4 + 5)相同,当然是27。

在第二个表达式中,+绑定到*的原始值,*未更改。因此(+ 3 (* 4 5))与原始绑定相当于(* 3 (* 4 5)),与中缀表达式3 * (4 * 5)相同,即60。

这里最重要的注意事项是let执行并行绑定。这意味着在(let ((+ *) (* +)) ...)之类的表达式中,首先获取*+的原始值,然后+*同时绑定 。这就是为什么新*值为+,而不是其新值。

我最近写了a post about the differences between the various let forms。请注意letlet*之间的差异。

答案 2 :(得分:1)

使用Stepper!

Racket有一个很好的步进器,可以帮助你回答这个问题。将您的代码粘贴到缓冲区中,切换到&#34;中级学生&#34;语言,然后单击&#34;步骤&#34;按钮。您将看到突出显示的步骤序列。

答案 3 :(得分:-1)

因为:

(let ((+ *)
      (* +))
  (+ 3 (* 4 5)))

严格等同于(这称为标识符重命名):

(let ((PLUS *)
      (TIMES +))
  (PLUS 3 (TIMES 4 5)))

因为,正如其他答案所指出的那样,绑定是并行完成的。 这意味着此处实际评估的表达式为:

(* 3 (+ 4 5)) 

确实是27。