我正在通过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
答案 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)
诚然,这并不令人满意,但它可以快速完成工作,让您专注于锻炼的重要部分,而不是摆弄解决方法。