Scheme 节目什么时候开始;交织定义和使用“;?

Scheme 节目什么时候开始;交织定义和使用“;?,scheme,lisp,definition,sicp,Scheme,Lisp,Definition,Sicp,他说: 在过程体中,嵌入的定义必须放在第一位。管理层不对运行混淆定义和使用的程序的后果负责 这到底意味着什么?我明白: “定义”指的是程序创建和价值分配 “一个程序主体”将被删除。它是过程定义中参数列表后面的代码 “嵌入式定义必须在过程体中放在第一位”是指“在过程体中创建和使用的任何定义必须放在其他定义之前” “interjune definition and use”是指“在定义过程或赋值之前调用它;” 然而,这种理解似乎与答案相矛盾,我可以将答案总结为“你的引用所指的错误是在程序主体开始

他说:

在过程体中,嵌入的定义必须放在第一位。管理层不对运行混淆定义和使用的程序的后果负责

这到底意味着什么?我明白:

  • “定义”指的是程序创建和价值分配
  • “一个程序主体”将被删除。它是过程定义中参数列表后面的代码
  • “嵌入式定义必须在过程体中放在第一位”是指“在过程体中创建和使用的任何定义必须放在其他定义之前”
  • “interjune definition and use”是指“在定义过程或赋值之前调用它;”
然而,这种理解似乎与答案相矛盾,我可以将答案总结为“你的引用所指的错误是在程序主体开始时使用依赖于该主体开始时定义的定义。这让我三次困惑:

  • 这种解释显然与我上面所说的相矛盾,但似乎有强有力的证据——编译规则——在其背后
  • SICP似乎乐于将定义与使用它们的其他定义放在一个正文中。只需查看
    sqrt
    过程
  • 乍一看,在我看来,链接问题作者的真正错误是将
    num prod
    视为他们定义的
    num
    中的一个值,而不是一个过程。然而,作者显然让它工作了,所以我可能错了

  • 到底发生了什么?误解在哪里?

    这是很微妙的,正如脚注和您提到的问题所暗示的,根据特定语言的实现,这些细节可能会有所不同

    这些问题将在本书后面(第3章和第4章)进行更详细的讨论,通常情况下,文本避免使用内部定义,以便在详细检查之前避免这些问题

    脚注上方代码之间的主要区别:

    (define (sqrt x)
      (define (good-enough? guess)
        (< (abs (- (square guess) x)) 0.001))
      (define (improve guess)
        (average guess (/ x guess)))
      (define (sqrt-iter guess)
        (if (good-enough? guess)
            guess
            (sqrt-iter (improve guess))))
      (sqrt-iter 1.0))
    
    前者中的所有定义都是过程定义,而
    num
    denom
    是值定义。程序体在调用该程序之前不会进行评估。但赋值时会对值定义进行求值

    具有值定义:

    (define sum (add 2 2))
    
    评估定义时将评估
    (添加2)
    ,如果是,则必须已定义
    add
    。但有一个程序定义:

    (define (sum n m) (add n m))
    
    程序对象将分配给
    sum
    ,但程序主体尚未计算,因此定义
    sum
    时不需要定义
    add
    ,但必须在调用
    sum
    时定义:

    (sum 2 2)
    
    正如我所说的,有很多子类型和很多变化,所以我不确定以下是否总是适用于方案的每个变化,但在“SICP方案”中,你可以说

    有效(定义的评估顺序不显著):

    同样有效的还有:

    ;procedure body
    (define (sum) (add 2 2))
    (define (add m n) (+ m n))
    (sum)
    
    通常无效(对
    define
    s的评估顺序很重要):

    以下各项是否有效取决于实施情况:

    ;procedure body
    (define (add m n) (+ m n))
    (define sum (add 2 2))
    
    最后是一个交织定义和使用的示例,这是否有效还取决于实现。IIRC,如果已经实施了,这将适用于本书第4章中描述的方案

    ;procedure body
    (sum)
    (define (sum) (add 2 2))
    (define (add m n) (+ m n))
    
    这是复杂而微妙的,但关键是:

  • 值定义的计算方式不同于过程定义
  • 砌块内部的行为可能不同于外部砌块
  • 方案实施之间存在差异
  • 这本书的设计让你在第三章之前不用太担心
  • 本书将在第4章详细介绍这一点

  • 你发现了这个计划的困难之一。和lisp。由于这种问题,没有单一的lisp,但出现了大量的lisp

    如果R5RS中的
    letrec
    -逻辑中的代码和R6RS中的
    letrec*
    -逻辑中不存在绑定形式,则语义未定义。也就是说,一切都取决于方案实施者的意愿

    请参阅论文FixedLetrec:Scheme递归绑定构造的忠实而高效的实现

    此外,您还可以阅读来自的讨论,当时方案的不同实施者之间没有达成普遍共识


    此外,麻省理工学院开发了两个版本的方案——学生版本和研究人员开发版本,它们在定义形式的顺序上表现不同。

    在给定程序的定义/代码中

    • “内部定义”是以
      define
      开头的表单
    • “过程主体”是以
      define
      开头的表单之后的所有其他表单
    • “嵌入定义必须在过程体中首先出现”是指所有内部
      define
      表单必须先出现,然后是所有其他内部表单。一旦出现非
      define
      内部表单,之后就不能出现内部
      define
      表单
    • “无交错使用”是指在定义任何名称之前,不得使用任何名称。假设所有内部
      define
      表单都被收集到一个等价的
      letrec
      ,并遵循其规则
    就是我们有,

    (define (proc args ...)
       ;; internal, or "embedded", definitions
       (define a1 ...init1...)
       (define a2 ...init2...)
       ......
       (define an ...initn...)
       ;; procedure body
       exp1 exp2 .... )
    
    任何
    ai
    都可以在任何
    initj
    表达式中使用,但只能在lambda表达式中使用。(*)否则它将在定义
    aj
    时引用
    ai
    的值,这是禁止的,因为在计算任何
    initj
    表达式时,认为尚未定义任何
    ai
    名称


    (*)Rem
    ;procedure body
    (define (add m n) (+ m n))
    (define sum (add 2 2))
    
    ;procedure body
    (sum)
    (define (sum) (add 2 2))
    (define (add m n) (+ m n))
    
    (define (proc args ...)
       ;; internal, or "embedded", definitions
       (define a1 ...init1...)
       (define a2 ...init2...)
       ......
       (define an ...initn...)
       ;; procedure body
       exp1 exp2 .... )
    
    (define proc 
       (lambda (args ...)
          ;; internal, or "embedded", definitions
          (letrec ( (a1 ...init1...)
                    (a2 ...init2...)
                    ......
                    (an ...initn...) )
            ;; procedure body
            exp1 exp2 .... 
            )))
    
                                       ;; or, equivalently,
    (define (my-proc x)                (define my-proc
                                         (lambda (x)
       (define (foo) a)                     (letrec ( (foo (lambda () a))
       (define a x)                                   (a x) )
       ;; my-proc's body                       ;; letrec's body
       (foo))                                  (foo))))
    
    (define (my-proc x)
       (define (foo) x)    ; `foo` is defined as a function
       (define a (foo))    ; `foo` is used by being called as a function
       a)