12

我正在通过 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

5 回答 5

7

在 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))))))
于 2012-11-27T20:33:28.513 回答
5

我要感谢 alinsoar、flamingo 和 Oscar 提供的非常有用的建议。

我决定采用 Oscar 的方法,它(显然)使用球拍图形库,而不是 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'函数将视口(基本上是一个窗口)作为参数,并创建一个函数,该函数采用两个坐标作为参数(以及一个我没有使用的可选颜色参数)。然而,在这种情况下,“坐标”并不是练习使用的简单向量。坐标是结构 'posn' 的实例,它基本上只是 x 和 y 值的包装器。

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

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

由于我正在进行的练习(2.49)涉及绘制关于水平轴对称的图形,所以这个小皱纹无关紧要,否则它可能会让你感到惊讶。我突然想到,解决这种“反转”的一种方法是使用书中的“翻转”功能,但我没有花时间去做。

再次感谢所有的帮助!

于 2012-11-28T18:59:45.037 回答
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 章练习的解决方案

于 2012-11-28T07:00:53.193 回答
1

对于大多数练习,从planet 加载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))))
于 2017-01-06T14:27:11.407 回答
0

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

#lang sicp
(#%require sicp-pict)

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

于 2021-06-30T15:02:24.027 回答