在DrRacket中编译SICP图片练习?

时间:2012-11-27 20:19:40

标签: scheme lisp racket sicp

我正在通过SICP进行自学,并参与第2章的图片语言部分。我一直在使用DrRacket进行早期练习,但是在尝试基于'绘制时进行练习时出现编译错误-line'图片功能在本书的这一部分。

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

(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

5 个答案:

答案 0 :(得分:6)

在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))))))

答案 1 :(得分:4)

我要感谢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)此库中的'draw-line'函数将视口(基本上是一个窗口)作为参数,并创建一个函数,该参数为参数提供两个坐标(以及我没有使用的可选颜色参数) 。然而,在这种情况下,'坐标'不是练习使用的简单向量。坐标是struct'posn'的实例,它基本上只是x和y值的包装器。

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

有趣的是,球拍图形库定义的视口坐标与我预期的略有不同。坐标(0 0)是框架中的顶部左点(我猜左下角),(11)是右下角。 (请注意,我在这里谈的是单位平方。在我在上面的代码中使用的框架中,右下角的真实坐标将是(500 500)。)

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

再次感谢所有帮助!

答案 2 :(得分:2)

我也使用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

答案 3 :(得分: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))))

答案 4 :(得分:0)

我的方法稍微简单一些: 尽管只是让它们都自己实现,但不要使用你自己对 Ex.2.49 的任何定义,而是使用你获得的内置函数

#lang sicp
(#%require sicp-pict)

诚然,这并不令人满意,但它可以快速完成工作,让您专注于锻炼的重要部分,而不是摆弄解决方法。

相关问题