-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSnowman.scrbl
789 lines (620 loc) · 22.9 KB
/
Snowman.scrbl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
#lang scribble/doc
@;;; Setup
@;;; =====
@(require racket/sandbox
scriblib/footnote
scribble/example
(prefix-in scribble-eval: scribble/eval)
scribble/manual
teachpack/2htdp/scribblings/img-eval
(for-label racket
pict pict/flash)
(for-syntax racket/base))
@(define my-evaluator
(make-img-eval))
@(define-syntax-rule (interact e ...)
(examples #:eval my-evaluator
#:label #f
e ...))
@(define-syntax-rule (interact-errors e ...)
(scribble-eval:interaction #:eval my-evaluator
e ...))
@;;; Main document
@;;; =============
@title{Building a snowman with Racket}
@author{Christopher Lemmer Webber}
This tutorial introduces some basics of programming in Racket and then
guides the user through making a snowman.
It assumes no previous computer science background or knowledge of math
beyond basic awareness of addition, subtraction and division (which aren't
used very much in this tutorial anyway!)
Racket is a fun programming environment and is suitable for
programmers of all experience levels (though this tutorial is aimed at
beginners). Let's dive in!
@section{Welcome to Racket!}
First you'll need to
@hyperlink["https://download.racket-lang.org/"]{install Racket}.
Then open the DrRacket program.
You'll see two main areas: one that starts out with @racketidfont{#lang racket}
(Racket includes many languages, but the default is called... "racket").
This is the "definitions" section, but we can think of it as the
"stuff to keep" section.
There's also the "interactions" section, which has a ">" prompt, but
we can think of it as the "playground" section.
Before we continue, make the "definitions" ("stuff to keep") section
look like this:
@; Maybe we should click
@codeblock|{
#lang racket
(require pict)
}|
@(examples #:eval my-evaluator
#:hidden #t
(require pict racket))
Now click "run", switch to the "interactions" section (the "playground")
and try running the following:
@interact[(circle 10)]
Do you see a circle ten pixels high? Cool, right?
Now let's try turning our circle red:
@interact[(colorize (circle 10) "red")]
We'll worry more about what this means later. For now, feel excited that
you've written your first Racket code!
@section{Racket basics}
Comments start with ";" and aren't evaluated:
@codeblock|{
;; I won't run, but hopefully I tell you something useful!
}|
Text is called a "string", because it's a "string of characters":
@codeblock|{
"I feel very stringy!"}|
Racket has all sorts of numbers, like integers and floating point:
@codeblock|{
42 ; integers
98.6 ; floating point
3/5 ; rational numbers
}|
We can add and multiply them and divide them:
@interact[
(+ 1 2)
(* 3 6)
(/ 10 2)]
This is interesting... this is called a "function call".
The first item in the parentheses is the function, so
@racket[+], @racket[*], and @racket[/] are functions to add, multiply
and divide numbers respectively.
The numbers we supply the functions are called "arguments".
We've seen this before:
@interact[(circle 10)]
@racket[circle] is also a function.
In this case we called @racket[circle] with the argument @racket[10]
because we wanted our circle to be ten pixels high.
Functions are like legos.
We can combine them together:
@interact[(+ 1 (* 2 3))]
Whoa... what's going on! Well, if we think about "substituting" each step,
this makes a lot of sense:
@codeblock|{
;; Hm... we need to simplify this!
(+ 1 (* 2 3))
;; Substitute (* 2 3) => 6
(+ 1 6)
;; Substitute (+ 1 6) => 7
7}|
With that in mind, we can understand our colorized circle from earlier:
@interact[
(circle 10)
(colorize (circle 10) "red")]
So @racket[colorize] is "transforming" the 10 pixel high circle and
turning it red... cool!
Functions are like that... they take an input, and return an output.
Here's another function:
@interact[
(string-append "book" "shelf")]
This function takes multiple strings as arguments as inputs and
squashes them down into one string as an output.
Functions are a lot like toasters: you put something in (bread), and
you get something out (toasted bread).
In fact, why don't we write our own toaster function?@note{
By now you may be finding it annoying to have to type and re-type
things in the interations area over and over again.
Consider using the keybindings "Alt + p" and "Alt + n"... they'll
allow you to go to "previous" and "next" definitions you've typed
before, and will save you a lot of typing.}
@interact[
(define (toaster str)
(string-append "toasted " str))
(toaster "bread")
(toaster "bagel")
(toaster (toaster "bread"))]
We can figure out how this works via substitution also.
When we pass in @racket["bread"], @racket[toaster] binds that to
@racket[str], so:
@codeblock|{
(toaster "bread")
;; becomes
(string-append "toasted " "bread")
;; becomes
"toasted bread"}|
What happens if we try to toast something that isn't a string?
@interact-errors[(toaster 123)]
That's an error! @racket[string-append] can only append strings!
We can raise our own errors:
@interact-errors[(error "Yuck!")]
Maybe it would be useful if we gave a more descriptive error when
we tried to feed our toaster something that isn't a string.
But first, we need to know... when is something a string?
Racket has functions that answer questions like this.
They usually end in a "?" character, and we call them "predicates".
Here's one called @racket[string?]:
@interact[
(string? "bread")
(string? 42)]
Oh that's interesting... we haven't seen @racket[#t] or @racket[#f] before.
Can guess what they mean?
If you guessed "true" and "false", you're right!
These are called "booleans".@note{
In Racket, everything that isn't @racket[#f] is technically true!}
Now that we have a way to check whether something is a string, we need
a way to conditionally do one thing if something is true and another if
something is false.
As it turns out, this kind of expression is called a "conditional",
and one such conditional is called @racket[if]!@note{Two other useful
conditionals are @racket[when] and @racket[cond], but we won't cover them
in this tutorial.}
@codeblock|{
(if (string? "bread") ; this is the "test"
"That looks like a string" ; run if true
"That's not a string!") ; run if false}|
Now that we have @racket[if] and @racket[string?] we can make a
better toaster:
@interact-errors[
(define (toaster str)
(if (string? str)
(string-append "toasted " str)
(error "Toasters can only toast strings!")))
(toaster "submarine sandwich")
(toaster 42)]
This is a good toaster!
It would be a shame if we lost it, so we should hold on to it.
To do so, copy the @racketidfont{toaster} function definition from the
interactive area and paste it into the definitions area.@note{
It's possible that the indentation won't look right when copying and pasting.
No problem... just highlight the code and press the "tab" key.}
(You may also want to save this to a file.)
Now your definitions area should look like:
@codeblock|{
#lang racket
(define (toaster str)
(if (string? str)
(string-append "toasted " str)
(error "Toasters can only toast strings!")))}|
Now press "run".
The interactive area will reset, but since we've defined toaster in
the definition area we can still run it:@note{
Another name for the interactions section / playground
is "REPL", which stands for "Read Eval Print Loop".
Racket users tend to find that it's convenient to experiment with
things at the REPL and then move them to the definitions area
once they mature.}
@interact[(toaster "bread")]
We've learned a lot about how Racket basics, and we've promised you that
we'll make a snowman.
We're almost there!
But first we should cover one more datastructure in Racket... lists!
@interact[(list "bread" "bagel" "sub")]
We can slice and dice lists with @racket[first], which pulls the first
item off a list, and @racket[rest], which returns the rest of the list:
@interact[
(first (list "bread" "bagel" "sub"))
(rest (list "bread" "bagel" "sub"))
(first (rest (list "bread" "bagel" "sub")))]
There is a function @racket[map], which can apply a function to each
item in a list.
Why not use @racket[map] on our friend @racket[toaster]?
@interact[
(map toaster (list "bread" "bagel" "sub"))]
@section{Building a snowman}
Now we know enough things to build a snowman.
Open a new file in DrRacket and @racketidfont{Save Definitions As...}
"snowman.rkt".
Make sure your definition includes the following,
@note{
By the way, we haven't described what @racket[require] means.
@racket[require] is a way to import other interesting "modules" or
"libraries" of code into our programs.
@racket[pict] is what lets us draw pictures in code, and there
are many other libraries that ship with Racket, as well as many more
@hyperlink["https://pkgs.racket-lang.org/"]{third party libraries}
that can be installed.}
and then click run:
@codeblock|{
#lang racket
(require pict)
}|
The most important ingredient for a snowman is, of course, a snowball.
Previously we used a @racket[circle] and that seems close, but circles
are transparent in the middle, so we should use a @racket[disk] instead.
Let's make a disk 50 pixels high:
@interact[(disk 50)]
Oops... we probably want to specify a color for our snowman.
Snow is usually white,@note{Of course, you can make your snowman
@hyperlink["https://docs.racket-lang.org/draw/color-database___.html"]{a different color}
if you prefer!}
so we can try that by specifying the color as a keyword argument:
@interact[(disk 50 #:color "white")]
Now we need to stack them.
Luckily the pict module comes with @racket[vc-append], which stands for
"vertical center append".
Well, we do want to stack things vertically, so let's try it!
@interact[
(vc-append
(disk 50 #:color "white")
(disk 65 #:color "white")
(disk 80 #:color "white"))]
That's a good start!
Except maybe we could make it a bit cleaner if we had a @racketidfont{snowball}
function.
Let's write one and give it one argument, @racketidfont{size}:
@interact[
(define (snowball size)
(disk size #:color "white"))
(vc-append
(snowball 50)
(snowball 65)
(snowball 80))]
That @racket[snowball] function seems useful.
Copy and paste it to your definitions area so you can keep it around.
In fact, it would be even cleaner if we gave each of our snowballs
names.
The top snowball seems to be the head, the middle snowball seems to
be the body, and the bottom snow ball seems to be the... butt?
Update your definitions area so that it looks like this:
@codeblock|{
#lang racket
(require pict)
;; Makes a snowball
(define (snowball size)
(disk size #:color "white"))
;; Snowman components
(define head
(snowball 50))
(define body
(snowball 65))
(define butt
(snowball 80))
;; Putting it all together
(define snowman
(vc-append head body butt))}|
@(examples #:eval my-evaluator
#:hidden #t
(define head
(snowball 50))
(define body
(snowball 65))
(define butt
(snowball 80))
(define snowman
(vc-append head body butt)))
This is interesting... we've seen @racket[define] used before to define
the functions @racket[toaster] and @racket[snowball].
But now we are defining variables (names that map to values) that
aren't functions.
If you look carefully you'll notice that the function uses of define
put parentheses around the first argument to @racket[define], whereas
the simple variable uses of @racket[define] do not.
We can now refer to these variables individually at the interaction area:
@interact[head snowman]
Unfortunately a snowman isn't a snowman without a face.
How do we make a face?
Well one oldschool way would be to make a text-based emoticon, like
so:
@interact[(text ":^)")]
Plus, now it has a caret for a carrot nose!
We can use @racket[cc-superimpose] (for "center center superimpose") to
see what it would look like on our head:
@interact[
(cc-superimpose
(snowball 50)
(text ":^)"))]
Oops, that doesn't look right.
It's too small, and it's turned the wrong way!
The first argument to text is @racketidfont{content}, but
@racket[text] can take up to three @emph{optional arguments}:
@racketidfont{style}, @racketidfont{size}, and @racketidfont{angle}.
Borrowing ideas from @racket[text]'s documentation, let's make it bold
and change the size:
@interact[(text ":^)" '(bold) 20)]
Better. But we still need to turn it.
The @racket[text] documentation says that we need to specify
@racketidfont{angle} in radians.
I hear @racket[pi] has something to do with circles and radians.
I wonder what happens if we use pi?
@interact[(text ":^)" '(bold) 20 pi)]
Oops, that turned fit all the way around.
What if we just wanted to turn it halfway around?
I guess that would be half of pi?
@interact[(text ":^)" '(bold) 20 (* pi 1/2))]
Gah! That's halfway, but in the opposite direction, so let's
try turning it... negative halfway?
@interact[(text ":^)" '(bold) 20 (* pi -1/2))]
Whew! That looks good. Let's try putting it on the head:
@interact[
(cc-superimpose
(snowball 50)
(text ":^)" '(bold) 20 (* pi -.5)))]
Well this is a much better head than we had before.
Let's switch back to the definitions window and replace our definition
for @racket[head] to use it:
@(examples
#:eval my-evaluator
#:label #f
#:no-prompt
(define head
(cc-superimpose
(snowball 50)
(text ":^)" '(bold) 20 (* pi -.5)))))
@;; Well, we aren't hitting "run" here, so we manually need to update
@;; the snowman
@(examples #:eval my-evaluator
#:hidden #t
(define snowman
(vc-append head body butt)))
Now hit "run".
Check in the interaction area.. did our head and our snowman update?
@interact[
head
snowman]
Now that we've figured out how to put rotated text on the head, we can
apply that same idea to add some "buttons" on the snowman's body:
@interact[
(text "* * *" '(bold) 20 (* pi -.5))
(cc-superimpose
(snowball 65)
(text "* * *" '(bold) 20 (* pi -.5)))]
That looks pretty good.
Let's update the definitions area to use this new body:
@(examples
#:eval my-evaluator
#:label #f
#:no-prompt
(define body
(cc-superimpose
(snowball 65)
(text "* * *" '(bold) 20 (* pi -.5)))))
@;; Update the snowman again
@(examples #:eval my-evaluator
#:hidden #t
(define snowman
(vc-append head body butt)))
@interact[snowman]
@emph{@bold{Exercise for the reader:}
Can you figure out how to make the buttons out of disks instead?
Hint: spacing them apart is the tricky part, but read the documentation
for @racket[vc-append] which can take an extra argument that can space
them apart for you.}
Our snowman is starting to look pretty good, but a snowman isn't a snowman
without twig arms.
The "Y" character looks kind of like a twig:
@interact[(text "Y")]
But that's way too small. Let's make it bigger and bold:
@interact[(text "Y" '(bold) 30)]
We also need to turn it to the left:
@interact[(text "Y" '(bold) 30 (* pi .5))]
We're so close, but this isn't the right color!
Brown would be better:
@interact[
(colorize (text "Y" '(bold) 30 (* pi .5))
"brown")]
But we also need a right arm.
When we rotated the face we learned that if we wanted to turn the face
to the right instead of the left, we needed to multiply @racket[pi] by
a negative number instead. So let's try that:
@interact[
(colorize (text "Y" '(bold) 30 (* pi -.5))
"brown")]
The code for making the left arm versus the right arm are exactly the
same except for the amount we're multiplying by pi.
Maybe we should try making a function that can make an arm for us, the
same way we did for @racket{snowball}.
Let's call it @racket{make-arm}, and it'll take one argument, the
amount to rotate:
@interact[
(define (make-arm rotate-amount)
(colorize (text "Y" '(bold) 30 (* pi rotate-amount))
"brown"))
(make-arm 0)
(make-arm 1)
(make-arm .5)
(make-arm -.5)]
Great... so this function is useful and those last two look like our
left and right arms.
Let's move @racket{make-arm} to the definitions area and define our
@racket{left-arm} and @racket{right-arm}, right above where we defined
the @racket[body]:
@codeblock|{
(define (make-arm rotate-amount)
(colorize (text "Y" '(bold) 30 (* pi rotate-amount))
"brown"))
(define left-arm
(make-arm .5))
(define right-arm
(make-arm -.5))}|
@(examples
#:eval my-evaluator
#:hidden #t
(define (make-arm rotate-amount)
(colorize (text "Y" '(bold) 30 (* pi rotate-amount))
"brown"))
(define left-arm
(make-arm .5))
(define right-arm
(make-arm -.5)))
Now we need to stick these stick-arms into the sides of our snowman.
If @racket[vc-append] means "vertical center append", then it makes sense
that @racket[hc-append] would mean "horizontal center append".
That sounds like what we want, so let's test if we can modify our body
definition to use it:
@interact[
(hc-append
left-arm
(cc-superimpose
(snowball 65)
(text "* * *" '(bold) 20 (* pi -.5)))
right-arm)]
That looks right, though it's getting a bit hard to read. Let's copy
this to the definitions area but add some comments so we remember
what each part means.
@codeblock|{
(define body
;; append the left arm, torso, and right arm horizontally
(hc-append
left-arm
;; make a snowball for the torso and put buttons on it
(cc-superimpose
(snowball 65)
;; asterisks are acceptable buttons, right?
(text "* * *" '(bold) 20 (* pi -.5)))
right-arm))}|
@;; Re-build the snowman
@(examples #:eval my-evaluator
#:hidden #t
(define body
;; append the left arm, torso, and right arm horizontally
(hc-append
left-arm
;; make a snowball for the torso and put buttons on it
(cc-superimpose
(snowball 65)
;; asterisks are acceptable buttons, right?
(text "* * *" '(bold) 20 (* pi -.5)))
right-arm))
(define snowman
(vc-append head body butt)))
Hit "run".
Now let's see what our snowman looks like in the interaction area:
@interact[snowman]
Horray! It works!
@emph{@bold{Exercise for the reader:}
You can keep improving your snowman!
For example, you could supply your snowman with a top hat made out of
@racket[filled-rectangle]s.
Or you could make a postcard by putting your snowman on a snowy
field with a sky and some "Happy Holidays" text.
You could even build a function that lets you customize the postcard's
message!}
At this point your code should look something like this:
@codeblock|{
#lang racket
(require pict)
;; Makes a snowball
(define (snowball size)
(disk size #:color "white"))
;; Snowman components
(define head
(cc-superimpose
(snowball 50)
(text ":^)" '(bold) 20 (* pi -.5))))
(define (make-arm rotate-amount)
(colorize (text "Y" '(bold) 30 (* pi rotate-amount))
"brown"))
(define left-arm
(make-arm .5))
(define right-arm
(make-arm -.5))
(define body
;; append the left arm, torso, and right arm horizontally
(hc-append
left-arm
;; make a snowball for the torso and put buttons on it
(cc-superimpose
(snowball 65)
;; asterisks are acceptable buttons, right?
(text "* * *" '(bold) 20 (* pi -.5)))
right-arm))
(define butt
(snowball 80))
;; Putting it all together
(define snowman
(vc-append head body butt))}|
@section{Where to go from here}
You've learned a lot about Racket!
But there is much more you can learn, and one of the most important things
you can do as a programmer is to learn to read documentation.
One important thing to know is you can right-click on many definitions in
the definition area in DrRacket and select @racketidfont{"View documentation for..."}
There are many resources, but here are some good starting points:
@itemlist[
@item{
@hyperlink["https://docs.racket-lang.org/quick/"]{
Quick: An Introduction to Racket with Pictures} --
This is a complimentary tutorial to this one in many ways.
It covers a few more advanced topics while remaining fairly introductory to
Racket.
It uses the same picture language we used here.}
@item{
@hyperlink["https://docs.racket-lang.org/guide/index.html"]{
The Racket Guide} --
A handy guide to all of Racket's core ideas!}
@item{
@hyperlink["https://docs.racket-lang.org/reference/index.html"]{
The Racket Reference} --
When you really want the details on how core tools in Racket work,
look here.}
@item{
@hyperlink["https://docs.racket-lang.org/continue/index.html"]{
Continue: Web Applications in Racket} --
Intermediate level tutorial where you learn to write web applications.}
@item{
@hyperlink["http://realmofracket.com/"]{
Realm of Racket} --
Learn to program Racket by making video games!
No prior programming experience required;
has the motto "For freshmen, by freshmen".}
@item{
@hyperlink["http://www.ccs.neu.edu/home/matthias/HtDP2e/"]{
How to Design Programs, Second Edition} --
A complete textbook for learning to program using Racket, made for
the classroom.
Teaches advanced topics without assuming prior programming knowledge.}]
That isn't enough? Can't stop learning?
Here are some more advanced resources:
@itemlist[
@item{
@hyperlink["https://docs.racket-lang.org/more/index.html"]{
More: Systems Programming with Racket} --
Writing a web application wasn't enough for you?
Why not write a web @emph{server} in Racket?}
@item{
@hyperlink["https://mitpress.mit.edu/books/little-schemer"]{
The Little Schemer} --
A good book for getting comfortable with recursion and understanding
how programming languages work (but not for learning how to write a
"practical" everyday style of Scheme (Racket's main language is a kind of
Scheme, which is a kind of Lisp, which is a kind of programming language
with parentheses)).
Written in a question and answer form, funny, and builds up deep topics
fast.
By the end of it, you'll write a version of Scheme in Scheme!}
@item{
@hyperlink["https://mitpress.mit.edu/sicp/"]{
Structure and Interpretation of Computer Programs} --
What used to be MIT's "introductory" computer science book, but don't
let that fool you... it's one of the most advanced (and fun) programming
books around.
Learn what the "soul" of the computer is... you'll learn core ideas,
and eventually will even write your own compiler!
Some nice resources online for it, including this
@hyperlink["https://sarabander.github.io/sicp/html/"]{
very pretty HTML version}
and
@hyperlink["https://archive.org/details/SICP_4_ipod"]{
original lectures from the 1980s}
can be found online.}]
See @hyperlink["https://racket-lang.org/"]{https://racket-lang.org/}
for more information, including how to talk to Racket's community.
Don't be afraid to reach out if you get stuck!
Racket is a good programming language environment for everyone from
beginners to experts.
Don't get intimidated by how much there is to know or give up if you
get stuck!
Racket is for everyone, including you... @emph{yes you!}