首页 文章

在DrRacket中编译SICP图片练习?

提问于
浏览
8

我将通过SICP进行自学,并参与第2章的图片语言部分 . 我一直在使用DrRacket进行早期练习,但在尝试基于“画线”进行练习时出现编译错误本书这一部分的图片功能 .

具体来说,这段代码......

(define (segments->painter segment-list)   
 (lambda (frame)     
  (for-each     
   (lambda (segment)        
    (draw-line         
     ((frame-coord-map frame) (start-segment segment))         
     ((frame-coord-map frame) (end-segment segment))))      
 segment-list)))

...产生这个错误......

draw-line: unbound identifier in module in: draw-line

所以我在这个论坛做了一些研究,并安装了Neil Van Dyke提供的SICP包(http://www.neilvandyke.org/racket-sicp/#(part._usage)) . 我按照所有步骤,按照指示将语言更改为SICP,但仍然得到相同的错误 .

我认为这个软件包的目的是定义这个“内置”函数(以及书中的其他函数) . 只是为了预测一些问题,我在文件中没有'require'语句并使用'#lang planet neil / sicp'来指定语言而不是使用菜单(我也尝试使用菜单将语言更改为SICP并获取一个更奇怪的错误;请参阅下面的附言) . 我的环境是Windows 7,DrRacket的版本是5.3.1 .

也许我只是犯了一个菜鸟错误;任何见解将不胜感激 .

谢谢 .

PS:对于那些感兴趣的人,当我使用菜单将语言设置为'SICP(PLaneT 1.17)'时,对于我尝试编译的任何定义(即使是最微不足道的),我都会收到以下错误...

<unsaved editor>:1:0: #%top-interaction: unbound identifier;
also, no #%app syntax transformer is bound in: #%top-interaction

4 回答

  • 1

    在Racket中,这些定义通过SICP第2章中的图纸解决了我的问题,之后我成功地解决了这些练习:

    (require graphics/graphics)
    (open-graphics)
    (define vp (open-viewport "A Picture Language" 500 500))
    
    (define draw (draw-viewport vp))
    (define (clear) ((clear-viewport vp)))
    (define line (draw-line vp))
    
    (define (make-vect x y)
      (cons x y))
    
    (define (xcor-vect v)
      (car v))
    
    (define (ycor-vect v)
      (cdr v))
    
    (define (add-vect v1 v2)
      (make-vect (+ (xcor-vect v1)
                    (xcor-vect v2))
                 (+ (ycor-vect v1)
                    (ycor-vect v2))))
    
    (define (sub-vect v1 v2)
      (make-vect (- (xcor-vect v1)
                    (xcor-vect v2))
                 (- (ycor-vect v1)
                    (ycor-vect v2))))
    
    (define (scale-vect s v)
      (make-vect (* s (xcor-vect v))
                 (* s (ycor-vect v))))
    
    
    (define (make-frame origin edge1 edge2)
      (list origin edge1 edge2))
    
    (define (origin-frame f)
      (car f))
    
    (define (edge1-frame f)
      (cadr f))
    
    (define (edge2-frame f)
      (caddr f))
    
    (define (frame-coord-map frame)
      (lambda (v)
        (add-vect
         (origin-frame frame)
         (add-vect (scale-vect (xcor-vect v)
                               (edge1-frame frame))
                   (scale-vect (ycor-vect v)
                               (edge2-frame frame))))))
    
  • 3

    我要感谢alinsoar,火烈鸟和奥斯卡提供的非常有用的建议 .

    我决定采用奥斯卡的方法(显然)使用球拍图形库,而不是由Neil Van Dyke组装的特殊包装(我根本没有运气) . 这是我的代码的重要部分(不依赖于图形库的定义):

    #lang racket
    (require graphics/graphics)
    (open-graphics)
    (define vp (open-viewport "A Picture Language" 500 500))
    
    (define draw (draw-viewport vp))
    (define (clear) ((clear-viewport vp)))
    (define line (draw-line vp))
    
    ;need a wrapper function so that the graphics library works with my code...
    (define (vector-to-posn v)
      (make-posn (car v) (car(cdr v))))
    
    (define (segments->painter segment-list)   
      (lambda (frame)     
       (for-each     
         (lambda (segment)        
          (line         
            (vector-to-posn ((frame-coord-map frame) (start-segment segment)))         
            (vector-to-posn ((frame-coord-map frame) (end-segment segment)))))      
          segment-list)))
    

    所以,有几点需要注意:

    1)如上所述,这使用标准的球拍语言,而不是Neil Van Dyke实施目的的SICP语言 .

    2)此库中的“绘制线”功能将视口(基本上是一个窗口)作为参数,并创建一个函数,该参数获取参数的两个坐标(以及我未使用的可选颜色参数) . 然而,在这种情况下,'坐标'不是练习使用的简单向量 . 坐标是struct'posn'的实例,它基本上只是x和y值的包装器 .

    这个posn数据类型的存在意味着我必须先用posn构造函数包装我的向量,然后才能在'segments-painter'函数中使用它们 . ('vector-to-posn'函数就是这个包装器) . 还要注意,书中对'segments-painter'的定义中使用的'draw-line'一词被'line'取代,'line'被定义为(draw-line vp) .

    3)有趣的是,球拍图形库定义的视口坐标与我预期的略有不同 . 坐标(0 0)是帧中的 top 左侧点(我猜左下角),(1 1)位于右下角 . (注意,这里我说的是单位平方 . 在我在上面的代码中使用的框架中,右下角的真实坐标将是(500 500) . )

    由于我正在进行的练习(2.49)涉及绘制关于水平轴对称的图形,这个小皱纹并不重要,但否则它可能会让你感到惊讶 . 在我看来,围绕这种“反转”的一种方法是使用书中的“翻转”功能,但我没有花时间去做 .

    再次感谢您的帮助!

  • 5

    我也使用DrRacket进行SICP练习 . 因此,为了使用绘图功能,您应该在源文件的顶部添加以下行:

    (require (lib "racket/draw"))
    (require racket/class)
    

    然后你应该设置图形上下文,如下所示:

    (define target (make-bitmap 100 100))
    (define dc (new bitmap-dc% [bitmap target]))
    

    在此之后你可以画一条线:

    (send dc draw-line
      (x1 y1) (x2 y2)
      (x3 y3) (x4 y4))
    

    并将结果保存到文件中:

    (send target save-file "foo.png" 'png)
    

    这是第2章练习的my solution

  • 1

    对于大多数练习来说,从行星加载sicp模块并在每个文件的顶部添加以下语言声明就足够了:

    #lang planet neil/sicp

    对于图片语言问题,请改用:

    #lang planet neil/sicp (#%require sicp-pict)

    缺少以下内容:

    波:

    (define wave
      (segments->painter
       (list
        (make-segment (make-vect 0.20 0.00) (make-vect 0.35 0.50))
        (make-segment (make-vect 0.35 0.50) (make-vect 0.30 0.60))
        (make-segment (make-vect 0.30 0.60) (make-vect 0.15 0.45))
        (make-segment (make-vect 0.15 0.45) (make-vect 0.00 0.60))
        (make-segment (make-vect 0.00 0.80) (make-vect 0.15 0.65))
        (make-segment (make-vect 0.15 0.65) (make-vect 0.30 0.70))
        (make-segment (make-vect 0.30 0.70) (make-vect 0.40 0.70))
        (make-segment (make-vect 0.40 0.70) (make-vect 0.35 0.85))
        (make-segment (make-vect 0.35 0.85) (make-vect 0.40 1.00))
        (make-segment (make-vect 0.60 1.00) (make-vect 0.65 0.85))
        (make-segment (make-vect 0.65 0.85) (make-vect 0.60 0.70))
        (make-segment (make-vect 0.60 0.70) (make-vect 0.75 0.70))
        (make-segment (make-vect 0.75 0.70) (make-vect 1.00 0.40))
        (make-segment (make-vect 1.00 0.20) (make-vect 0.60 0.48))
        (make-segment (make-vect 0.60 0.48) (make-vect 0.80 0.00))
        (make-segment (make-vect 0.40 0.00) (make-vect 0.50 0.30))
        (make-segment (make-vect 0.50 0.30) (make-vect 0.60 0.00)))))
    

    罗杰斯:
    替换为替代原语 einstein

    如果您还想为练习2.49实现自己版本的sicp-pict模块,可能最简单的方法是在htdp教学语言中使用图像库 . 将以下内容放在程序的顶部:

    #lang sicp
    (#%require 2htdp/image)
    (#%require lang/posn)
    (#%require racket/base)
    
    (define *current-image* empty-image)  
    
    (define (*new-image* new-frame)
      (define (xy->posn x y)
        (let ((v ((frame-coord-map new-frame) (make-vect x y))))
          (make-posn (xcor-vect v) (ycor-vect v))))
      (set! *current-image*
            (polygon
             (list
              (xy->posn 0 0)
              (xy->posn 0 1)
              (xy->posn 1 1)
              (xy->posn 1 0))
             "solid"
             "white")))  
    
    (define (draw-line start end)
        (set! *current-image*
            (add-line
             *current-image*
             (xcor-vect start)
             (ycor-vect start)
             (xcor-vect end)
             (ycor-vect end)
             "black")))  
    
    (define (paint-in-frame painter frame)
        (*new-image* frame)
        (painter frame)
        *current-image*))  
    
    (define (paint painter)
        (paint-in-frame
            painter
            (make-frame
                (make-vect 0 150)
                (make-vect 150 0)
                (make-vect 0 -150))))
    

相关问题