代码之家  ›  专栏  ›  技术社区  ›  Jeroen

仅当定义两次时,程序才起作用

  •  0
  • Jeroen  · 技术社区  · 6 年前

    我定义了 map 程序和a square 程序这个 广场 程序运行正常,但 地图 只有定义两次,一个才有效。

    给定以下代码:

    ; Squares a number.
    (define square (lambda (n)
        (* n n)
    ))
    
    
    ; Applies function f on all elements of l.
    (define map (lambda (l f)
        (cond
            ((null? l) '())
            (else (cons (f (car l)) (map (cdr l) f)))
        )
    ))
    

    此程序在执行时崩溃:

    > (map '(1 2 3) square)
    ; mcar: contract violation
    ;   expected: mpair?
    ;   given: #<procedure:square>
    ; [,bt for context]
    

    但是,如果给定以下代码,程序将按预期工作。唯一的区别是 地图 现在定义了两次。

    ; Squares a number.
    (define square (lambda (n)
        (* n n)
    ))
    
    
    ; Applies function f on all elements of l.
    (define map (lambda (l f)
        (cond
            ((null? l) '())
            (else (cons (f (car l)) (map (cdr l) f)))
        )
    ))
    
    (define map (lambda (l f)
        (cond
            ((null? l) '())
            (else (cons (f (car l)) (map (cdr l) f)))
        )
    ))
    

    此版本工作正常:

    > (map '(1 2 3) square)
    {1 4 9}
    

    是什么导致了这个问题,应该如何解决?

    2 回复  |  直到 6 年前
        1
  •  4
  •   John Clements    6 年前

    我无法再现你的问题。具体来说,我在DrRacket中运行此程序:

    #lang r5rs
    
    ; Squares a number.
    (define square (lambda (n)
        (* n n)
    ))
    
    
    ; Applies function f on all elements of l.
    (define map (lambda (l f)
        (cond
            ((null? l) '())
            (else (cons (f (car l)) (map (cdr l) f)))
        )
    ))
    

    然后,在交互窗口中,我运行

    > (map '(3 4 5) square)
    

    ... 并得到结果:

    (mcons 9 (mcons 16 (mcons 25 '())))
    

    你能提供更多的信息来帮助重现你的问题吗?(您提到的mcons清楚地表明,您正在使用racket和命令行运行此代码,但我猜您加载和运行代码的方式有点可笑。)

    编辑:好的,我现在可以复制类似的内容,只需将这些表达式一个接一个地粘贴到REPL中。显然,我已经很久没有使用顶级REPL了。不管你的问题的答案是什么,更高层次的答案是:不要将表达式粘贴到REPL中。用MatthewFlatt(Racket的主要实现者)的话来说,“顶级是没有希望的。”使用DrRacket是解决此问题的最简单方法。

    编辑2:正如我所怀疑的,TL;博士:1)顶层是没有希望的。2) 将所有代码放在模块中。

    我在Racket用户列表的帖子中总结了一些这种混淆。具体而言,根本问题是:绑定的右侧如何不在绑定本身的范围内?

    以下是马修回答的摘录:


    这就是问题的本质所在。哪些内容属于 顶级定义?

    例如,是对 f 在以下约束范围内: f 在里面

    (define (g x) (f x))
    (define (f x) x)
    

    ?

    进来怎么样

    (begin
      (define (g x) (f x))
      (define (f x) x))
    

    ?

    或在中

    (expand '(define (f x) x))
    (define (g x) (f x))
    

    (begin
     (expand '(define (f x) x))
     (define (g x) (f x)))
    

    ?

    球拍的规则是 define 不会改变 标识符的绑定,直到 定义 已评估。所以,在

    (define (map x) ... map ...)
    

    参考 map 在以下位置展开/编译 地图 引用模块导入,而不是名为 地图 . 到 定义已评估,现在重新定义 地图 作为导入的引用。

    还有其他选择,但我认为没有 最终变得更好或更一致。顶层为 绝望的

    模块的表现明显更好,部分原因是 定义很明确:从模块开始到结束。


    在这一点上,你可能会问自己 应该与球拍互动。有几个不错的选择:

    1) 使用DrRacket。我对这个建议太高了。 2) 使用命令行,并使用“require”而不是“load”。“load”并不是说得太细,它是对该语言旧版本的半破坏性保留。

    例如,我可以将此代码放在一个名为“a.rkt”的文件中:

    #语言r5rs
    
    ; 将数字平方。
    (定义正方形(λ(n))
    (*n n)
    ))
    
    
    ; 将函数f应用于l的所有元素。
    (定义贴图(λ(l f))
    (康德
    ((null?l)“”())
    (其他(cons(f(car l))(map(cdr l)f)))
    )
    ))
    

    然后,我启动racket并“要求”此模块,然后使用“回车”进入模块:

    hardy:/tmp clements> racket
    Welcome to Racket v6.11.0.6.
    > (require "a.rkt")
    > ,enter "a.rkt"
    "a.rkt"> (map '(3 4 5) square)
    (mcons 9 (mcons 16 (mcons 25 '())))
    "a.rkt"> 
    

    让我再次重申,您通过简单地使用DrRacket来回避所有这些问题。

    所以我今天学到了很多!谢谢

        2
  •  1
  •   Barmar    6 年前

    map 是标准方案函数。当你第一次定义这个函数时,它显然是在试图调用标准函数,而不是你对它的重新定义。因为标准函数的参数顺序相反 (map function list) ,它得到一个错误。第二次定义它时,它会在环境中找到您的功能,所以一切正常。

    最好的解决方案是使用与标准函数不冲突的其他名称。

    推荐文章