-
Notifications
You must be signed in to change notification settings - Fork 24
/
i1prog.tex
1974 lines (1801 loc) · 71.5 KB
/
i1prog.tex
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
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
% Diese Datei ist Teil des Buchs "Schreibe Dein Programm!"
% Das Buch ist lizenziert unter der Creative-Commons-Lizenz
% "Namensnennung - Weitergabe unter gleichen Bedingungen 4.0 International (CC BY-SA 4.0)"
% https://creativecommons.org/licenses/by-sa/4.0/deed.de
\chapter{Elemente des Programmierens}
\label{cha:whats-programming}
Dieses Kapitel gibt einen Überblick über das wichtigste Handwerkszeug
des Programmierens. Für den Einstieg solltest Du Racket
heruntergeladen haben. In
Abschnitt~\ref{sec:racket} auf Seite~\pageref{sec:racket} steht wo.
\section{DrRacket}
\begin{figure}[tb]
\centering
\includegraphics[width=\textwidth]{elemente/drracket-start}
\caption{DrRacket nach dem ersten Start}
\label{fig:drracket-start}
\end{figure}
Zu Racket gehört ein Programm namens
\textit{DrRacket}\index{DrRacket}: starte es. Es erscheint ein
Fenster, das ungefähr so aussehen sollte wie in
Abbildung~\ref{fig:drracket-start}. Die Benutzeroberfläche kannst
Du auf Deutsch umstellen, indem Du im \texttt{Help}-Menü auf \texttt{Deutsche
Benutzeroberfläche für DrRacket} drückst. Wenn Du die Auswahl
bestätigst, wird DrRacket danach beendet und Du musst es noch einmal
starten; dann sollten die Menüs auf Deutsch sein.
DrRacket ist eine \textit{Entwicklungsumgebung}, mit der Du Programme
schreiben und ausführen kannst. DrRacket unterstützt nicht nur eine
einzige Programmiersprache, sondern viele.
Darum musst Du die richtige Programmiersprache für
dieses Buch noch auswählen. Wähle dazu den Menüpunkt
\texttt{Sprache $\rightarrow$ Sprache auswählen} (\texttt{Language $\rightarrow$ Choose language} in der englischen
Fassung), worauf ein neues Fenster mit einem Dialog erscheint.
In dem Dialog gibt es eine
Abteilung \texttt{Lehrsprachen\index{Lehrsprachen}}, und darunter eine
Überschrift namens \texttt{DeinProgramm}, unterhalb dessen mehrere
Einträge erscheinen, die speziell auf die Kapitel dieses Buchs
zugeschnitten sind.
\begin{figure}[tb]
\centering
\includegraphics[width=\textwidth]{elemente/drracket-deinprogramm}
\caption{DrRacket mit ausgewählter Lehrsprache}
\label{fig:drracket-deinprogramm}
\end{figure}
Für den ersten Teil des Buchs ist die Ebene \texttt{Schreibe Dein
Programm! - Anfänger} zuständig:\index{Sprachebene!Anfänger} Wähle
diese aus und drücke dann einmal oben rechts auf den Knopf
\texttt{Start} (beziehungsweise \texttt{Run}), damit die Auswahl aktiv wird.
Das Ergebnis sollte dann so aussehen wie in
Abbildung~\ref{fig:drracket-deinprogramm}.
Das DrRacket-Fenster besteht aus zwei Teilen:
%
\begin{enumerate}
\item In der oberen Hälfte des Fensters (dem
\textit{Editor-\index{Editor}} oder
\textit{Definitionsfenster\index{Definitionsfenster}}) steht der
Programmtext. Der Editor funktioniert ähnlich wie ein reguläres
Textverarbeitungsprogramm. Was dort steht, kannst Du abspeichern.
Wenn Du ein Programm abspeicherst, benutze die Endung \texttt{.rkt}
für "<\textbf{R}ac\textbf{k}e\textbf{t}">.
\item In der unteren Hälfte des Fensters~-- dem
\textit{Interaktionsfenster\index{Interaktionsfenster}} oder der
sogenannten \textit{REPL\index{REPL}}\footnote{"<REPL"> steht für
"<Read-Eval-Print-Loop">~-- wir werden später zeigen, warum.}
werden die Ausgaben des Programms angezeigt. Außerdem kannst Du
einzelne Programmteile gezielt testen.
\end{enumerate}
%
\section{Ausdrücke und die REPL}
Fangen wir mit der REPL an: Wenn Du gerade \texttt{Start} gedrückt
hast, dann erscheint der Cursor rechts von dem \lstinline{>}-Zeichen:
Hier kannst Du etwas eingeben und Return drücken. DrRacket zeigt dann
das Ergebnis darunter an.
Wenn Du zum Beispiel \lstinline{123} eintippst, zeigt DrRacket gleich
darunter 123 an. DrRacket kann auch rechnen. Dafür musst Du
allerdings die Rechenaufgaben etwas anders aufschreiben als sonst.
Zum Beispiel so:
%
\begin{lstlisting}
(+ 123 42)
\end{lstlisting}
%
Wenn Du das in die REPL eingibst, zeigt DrRacket \lstinline{165} an, die
\textit{Summe}\index{Summe} von 123 und 42. Diese "<Rechenaufgabe">
ist ein sogenannter \textit{Ausdruck\index{Ausdruck}}. Ausdrücke, die
etwas ausrechnen sollten, haben in den Lehrsprachen immer die gleiche
Form:
%
\begin{lstlisting}
(|\textnormal{\textit{Operator}}| |\textnormal{\textit{Operand}}| |\ldots|)
\end{lstlisting}
%
Es stehen \emph{immer} Klammern\index{Klammer} drumherum
(und die können auch nirgendwo sonst stehen). Dann folgt der
\textit{Operator\index{Operator}}, der bestimmt, \emph{was} gemacht
wird (die \textit{Operation}). Danach kommen die
\textit{Operanden\index{Operand}}, welche die Eingaben\index{Eingabe}
für die Operation bestimmen.
Zum Merken ist es hilfreich, Ausdrücke entsprechend vorzulesen: Also
nicht mehr "<hundertdreiundzwanzig plus zweiundvierzig">, sondern
"<die \emph{Summe} von hundertdreiundzwanzig und zweiundvierzig">.
Wenn Du Klammern vergisst,
können verwirrende Ergebnisse herauskommen. Wenn Du zum Beispiel
\lstinline{+ 123 42} in der REPL eintippst, sieht das so aus:
%
\begin{alltt}
> + {\color{DarkGreen}123 42}
{\color{blue}#<function:+>
123
42}
\end{alltt}
%
Das liegt daran, dass ohne Klammern \lstinline{+ 123 32} aus \emph{drei}
Ausdrücken besteht und die REPL deshalb auch drei Ergebnisse ausdruckt:
Die Funktion \lstinline{+}, dann die \lstinline{123}, dann \lstinline{42}.
(Die Operation \lstinline{+} ist eine sogenannte Funktion~-- das
erläutern wir später noch genauer.) Ähnlich verhält es sich mit
\lstinline{123 + 42}~-- probiere es aus!
Wenn Du versehentlich die Klammern setzt, aber den Operator dazwischen
schreibst, erscheint in der REPL eine Fehlermeldung:
%
\begin{alltt}
> ({\color{DarkGreen}123} + {\color{DarkGreen}42})
{\color{red}Operator darf keine Zahl sein, ist aber 123}
\end{alltt}
%
Etwas ähnliches passiert, wenn das Leerzeichen zwischen dem
Operator und den Operanden fehlt~-- oder zwischen den Operanden. Das
sieht zum Beispiel so aus:
%
\begin{alltt}
> ({\color{DarkGreen}+123} {\color{DarkGreen}42})
{\color{red}Operator darf keine Zahl sein, ist aber 123}
\end{alltt}
%
Das liegt daran, dass \lstinline{+123} zusammen die Zahl "<plus
hundertdreiundzwanzig"> bildet und nicht etwa in das \lstinline{+}-Zeichen und
\lstinline{123} aufgeteilt wird.
Wenn ein Ausdruck wie \lstinline{(+ 123 42)} ein Ergebnis wie 165 hat,
schreiben wir das im Buch zukünftig so, etwas anders als die
DrRacket-REPL:
%
\begin{lstlisting}
(+ 123 42)
|\evalsto| 165
\end{lstlisting}
%
So lassen sich natürlich nicht nur Summen, sonderen auch Differenzen,
Produkte (mit dem Operator \lstinline{*}) und Quotienten (mit dem
Operator \lstinline{/}) ausrechnen:
%
\begin{lstlisting}
(- 123 42)
|\evalsto| 81
(* 123 42)
|\evalsto| 5166
(/ 123 42)
|\evalsto| 2.9$\overline{\mathtt{285714}}$
\end{lstlisting}
%
Beim letzen Ausdruck ist zu sehen, dass Dezimalzahlen mit Punkt und
nicht mit Komma geschrieben werden. Der Überstrich bei
\lstinline{2.9$\overline{\mathtt{285714}}$} ist eine
\textit{Periode\index{Periode}}. Die Zahl ist also eigentlich
%
\begin{lstlisting}
2.9285714285714285714285714285714|\ldots|
\end{lstlisting}
%
Die REPL funktioniert also folgendermaßen: Sie \emph{liest} einen
Ausdruck ein (auf Englisch "<read">), berechnet dessen Wert oder \emph{wertet}
diesen \emph{aus} ("<eval">, kurz für "<evaluate">) und zeigt das Ergebnis an
oder \emph{druckt} dieses \emph{aus} ("<print">)~-- und dann geht es
von vorn los, wie in einer Schleife ("<loop">). Die Abfolge
\emph{Read-Eval-Print-Loop} gibt der REPL ihren Namen.
Ausdrücke können auch kombiniert werden, zum Beispiel so:
%
\begin{lstlisting}
(* 123 (+ 20 22))
|\evalsto| 5166
(* 123 (+ (* 2 10) 22))
|\evalsto| 5166
\end{lstlisting}
%
Bei der Kombination verschiedener Ausdrücke ist es wichtig,
dass um jeden Teilausdruck wieder ein
Klammernpaar kommt. Ist das nicht der Fall, erscheinen gelegentlich
auch mal Fehlermeldungen wie diese hier:
%
\begin{lstlisting}
(* 123 (+ * 2 10 22))
|\color{red}\texttt{+: Zahl als erstes Argument erwartet, \#<function:*> bekommen}|
\end{lstlisting}
%
Das liegt daran, dass das \lstinline{*} hier an der Stelle eines
Operanden steht. Das Wort \textit{Argument} steht für
den Wert des Operanden einer Funktion, darum steht da sinngemäß, dass
\lstinline{+} eine Zahl als erstes Argument etwartet, aber
stattdessen die Funktion \lstinline{*} bekommen hat. (Das Wort
"<Argument"> definieren wir genauer in Abschnitt~\ref{sec:argument} auf
Seite~\pageref{sec:argument}.)
Abspeichern geht mit der REPL nicht, und der REPL-Inhalt verschwindet
auch jedesmal, wenn Du \texttt{Start} beziehungsweise \texttt{Run} drückst. Du
kannst aber frühere Eingaben zurückholen, indem Du
\texttt{Strg-$\uparrow$} beziehungsweise \texttt{Control-$\uparrow$}
(je nach Computertyp) drückst. (Das geht natürlich auch nach unten
mit \texttt{Strg-$\downarrow$} beziehungsweise
\texttt{Control-$\downarrow$}.)
Das kannst Du auch benutzen, um einen
fehlerhaften Ausdruck zu korrigieren, bei dem Du schon Return gedrückt hast.
\begin{aufgabeinline}
Schreibe folgende "<mathematischen"> Ausdrücke in der Notation der
Lehrsprache in die REPL und lasse die REPL sie auswerten:
%
\begin{displaymath}
\begin{array}{c}
55 * 27\\
23 * (44 + 27)\\
\frac{23}{44} + \frac{44}{23}\\
(23 + 42) * (12 + (14 * 2))
\end{array}
\end{displaymath}
\end{aufgabeinline}
%
\section{Das Definitionsfenster}
Kommen wir zum Definitionsfenster oben. Dort schreibst Du Dein
Programm, die REPL kannst Du dann benutzen, um es auszuprobieren.
Schreib in das Definitionsfenster folgende
\textit{Definition\index{Definition}}:
%
\begin{lstlisting}
(define alles (+ 20 22))
\end{lstlisting}
%
Diese Definition besagt, dass der Name \lstinline{alles} für das Ergebnis
von \lstinline{(+ 20 22)} steht. Um das auszuprobieren, drück auf den
Knopf \texttt{Start} beziehungsweise \texttt{Run} rechts oben. Der Cursor
landet dann wieder in der REPL, wo Du das Programm ausprobieren
kannst:
%
\begin{lstlisting}
alles
|\evalsto| 42
\end{lstlisting}
%
Ein solcher Name in einem Programm heißt
\textit{Variable\index{Variable}}.\footnote{Obwohl der Begriff
"<Variable"> suggeriert, dass etwas daran verändert werden
kann, bleibt der Wert einer Variable immer gleich.}
Hier sind ein paar weitere Beispiele für Definitionen von Variablen:
%
\begin{lstlisting}
(define one 1)
(define temperature 23)
(define birgit-prinz 9)
\end{lstlisting}
%
Du kannst auch diese Namen in die REPL eingeben und bekommst
jeweils den dazugehörigen Wert, wenn Du Return drückst:
%
\begin{lstlisting}
one
|\evalsto| 1
temperature
|\evalsto| 23
birgit-prinz
|\evalsto| 9
\end{lstlisting}
%
Bei der Gestaltung eines Namens gibt es weitgehende Freiheiten. Anders
als in anderen Programmiersprachen sind auch Bindestriche in Namen
möglich. Nur Leerzeichen sind nicht erlaubt.
Groß- und Kleinschreibung ist bei Namen egal. Es funktioniert also
auch:
%
\begin{lstlisting}
Alles
|\evalsto| 42
ONE
|\evalsto| 1
tEmPeRaTuRe
|\evalsto| 23
\end{lstlisting}
%
In einem Programm kannst Du Zeilenumbrüche und Einrückung benutzen, um
Dein Programm übersichtlicher zu gestalten. Zum Beispiel kannst Du
nach \lstinline{alles} die Return-Taste drücken, das Ergebnis sieht so
aus:
%
\begin{lstlisting}
(define alles
(+ 20 22))
\end{lstlisting}
%
DrRacket rückt die zweite Zeile ein bisschen ein, um auszudrücken,
dass sie noch in die Klammern vom \lstinline{define} gehört. Bei
komplizierteren Ausdrücken ist das hilfreich:
%
\indexvariable{alles}
\begin{lstlisting}
(define alles
(+ 20
(* 11 2)))
\end{lstlisting}
%
Hier stellt DrRacket die Operanden der Summe genau untereinander.
DrRacket zwingt Dich nicht, die Einrückung genau so zu machen, und
durch Änderungen im Programm gerät sie auch manchmal aus dem Lot. In
dem Fall kannst Du die Tab-Taste drücken (auf den meisten Tastaturen
steht $\longrightarrow\mid$ auf der Tab-Taste) und in der Zeile, in
welcher der Cursor steht, wird die Einrückung korrigiert.
Wenn Du einen Abschnitt im Programm markierst und dann Tab drückst,
wird der ganze Abschnitt neu eingerückt.
Es gibt
außerdem einen Menüpunkt \texttt{Racket $\rightarrow$ Alles einrücken} (beziehungsweise
\texttt{Racket $\rightarrow$ Reindent All}), der das für das gesamte
Programm macht.
Ein weiterer praktischer Trick ist, dass Du einen geklammerten
Ausdruck markieren (und dann ausschneiden) kannst, indem Du auf die
öffnende oder schließende Klammer doppelt klickst. Insbesondere
kannst Du den markierten Ausdruck dann mit einem Druck auf die
Tab-Taste korrekt einrücken.
\begin{aufgabeinline}
Bring bei einem mehrzeiligen Programm die Einrückung richtig
durcheinander, zum Beispiel so:
\begin{lstlisting}
(define nr
(+ 12
(- (* 42
13)
500)))
\end{lstlisting}
%
Benutze dann die Tab-Taste, um die Einrückung wieder zu korrigieren.
\end{aufgabeinline}
%
Den Inhalt des Definitionsfensters kannst Du abspeichern, indem Du auf
den Knopf mit dem Diskettensymbol
\raisebox{-1ex}{\includegraphics[height=12pt]{elemente/save}}\footnote{Disketten
wurden im 20.~Jahrhundert verwendet, um Daten zu speichern. Es gab
damals noch keine Speicherkarten oder USB-Sticks.}
drückst. Du bekommst dann ein Dialogfenster, in dem Du einen
Dateinamen vergeben kannst.
\section{Rechnen ohne Zahlen}
Computerprogramme können nicht nur mit Zahlen rechnen. In diesem
Abschnitt geht es um das Rechnen mit Text und das Rechnen mit Bildern.
\subsection{Rechnen mit Text}
Aus Text\index{Text} kann durch doppelte Anführungszeichen ein Wert werden:
%
\begin{lstlisting}
"Mike Sperber"
"Herbert Klaeren"
"Schreibe Dein Programm!"
\end{lstlisting}
%
Solche Text-Werte heißen \textit{Zeichenketten\index{Zeichenkette}}.
Die einfachste Art, eine Zeichenkette herzustellen, ist, die
Buchstaben hinzuschreiben, aus denen sie besteht. Die
Anführungszeichen müssen drumherum, damit die Zeichenketten von anderen
Ausdrücken unterschieden werden können. Die Anführungszeichen gehören aber nicht
zu den Buchstaben dazu, aus denen die Zeichenkette besteht~--
\lstinline{"abc"} besteht aus den drei Buchstaben \texttt{abc}.
\begin{feature}{Zeichenketten}{scheme:strings}
\textit{Zeichenketten\index{Zeichenkette}} (auf Englisch
\textit{Strings}\index{String}) repräsentieren Text.
Literale für Zeichenketten haben folgende Form:
%
\begin{lstlisting}
"$z\sb{1}$$z\sb{2}$ $\ldots$ $z\sb{n}$"
\end{lstlisting}
%
Dabei sind die \(z\sb{i}\) beliebige einzelne Zeichen, außer \lstinline{"} selbst.
Beispiel:
%
\begin{lstlisting}
"Herbert was here!"
\end{lstlisting}
%
Das Anführungszeichen (\lstinline{"}) kann nicht "<ungeschützt"> vorkommen, da es das Ende der
Zeichenkette markiert. Es wird als "<echtes"> Anführungszeichen innerhalb einer Zeichenkette
durch \lstinline{\"} dargestellt:
%
\begin{lstlisting}
"Herbert sagt |\backwhack|"Hallo Mike|\backwhack|"!"
\end{lstlisting}
\end{feature}
Abbildung~\ref{scheme:strings} beschreibt die genaue Schreibweise für
solche "<festen"> Zeichenketten. Feste Schreibweisen für Werte heißen
allgemein \textit{Literale\index{Literal}}. Das kennen wir schon von
den Zahlen: Die Zeichenfolge \lstinline{123} steht für die Zahl
"<hundertdreiundzwanzig">. Kästen wie Abbildung~\ref{scheme:strings}
werden in diesem Buch noch oft dazu dienen, neue Sprachelemente
einzuführen.
Mit Text kann ein Programm auch rechnen, und zwar mit der eingebauten
Funktion
\texttt{string"=append}\indexvariable{string-append},
die zwei Zeichenketten aneinanderhängt:
%
\begin{lstlisting}
(string-append "Herbert" "Mike")
|\evalsto| "HerbertMike"
(string-append "Mike" " " "ist doof")
|\evalsto| "Mike ist doof"
\end{lstlisting}
%
Die eingebaute Funktion
\lstinline{string-length}\indexvariable{string-length}
liefert die Anzahl der Zeichen in einer Zeichenkette:
%
\begin{lstlisting}
(string-length "Herbert")
|\evalsto| 7
(string-length "Mike")
|\evalsto| 4
\end{lstlisting}
%
Die Namen \lstinline{string-append} und \lstinline{string-length} sehen auf
den ersten Blick "<anders"> aus als \lstinline{+} und \lstinline{*} zum
Beispiel, dieser Eindruck täuscht jedoch: Sie sind allesamt Namen von
vordefinierten Operationen, die Programme benutzen können, ohne sie
selbst definieren zu müssen.
Die vordefinierten Funktionen
\lstinline{string->number}\indexvariable{string->number}
und \lstinline{number->string} konvertieren zwischen Zahlen und den
Zeichenketten, die diese darstellen:
%
\begin{lstlisting}
(string->number "23")
|\evalsto| 23
(number->string 23)
|\evalsto| "23"
\end{lstlisting}
%
\begin{aufgabeinline}
Mache Dir den Unterschied zwischen der Zahl \lstinline{23} und der
Zeichenkette \lstinline{"23"} klar. Probiere zum Beispiel aus:
\begin{lstlisting}
(+ "23" 42)
(string-append 23 "42")
(number->string "23")
\end{lstlisting}
\end{aufgabeinline}
\subsection{Rechnen mit Bildern}
\label{sec:rechnen-mit-bildern}
Programme können auch mit Bildern rechnen. Dazu wird eine Erweiterung
zu DrRacket benötigt, ein sogenanntes
\textit{Teachpack}\index{Teachpack}. Um es zu aktivieren, wähle den Menüpunkt
\texttt{Sprache $\rightarrow$ Teachpack hinzufügen}
(\texttt{Language $\rightarrow$ Add Teachpack}). In dem folgenden Dialog
wähle \texttt{image.rkt} aus und drücke
\texttt{OK}. Dann musst Du noch einmal auf \texttt{Start} drücken.
Wenn alles geklappt hat, steht unten in der REPL
\texttt{Teachpack: image.rkt}.
Das Teachpack \texttt{image.rkt} enthält zusätzliche vordefinierte
Funktionen, mit denen wir Bilder herstellen können. Zum Beispiel
\lstinline{square}, \lstinline{circle} und \lstinline{star-polygon}:
%
\begin{lstlisting}
(square 40 "solid" "red")
|\evalsto| |\includegraphics[height=24pt]{elemente/square}|
(circle 20 "solid" "green")
|\evalsto| |\includegraphics[height=24pt]{elemente/circle}|
(star-polygon 20 10 3 "solid" "blue")
|\evalsto| |\includegraphics[height=24pt]{elemente/starpolygon}|
\end{lstlisting}
%
Schauen wir uns das eingebaute \lstinline{star-polygon} etwas näher an:
Es akzeptiert fünf Eingaben, die ersten drei davon sind Zahlen~-- die
Seitenlänge, die Seitenanzahl und die Anzahl der Ecken, die für jede
Seite übersprungen wird. Danach kommen zwei Zeichenketten~--
\lstinline{"solid"} heißt, dass das Innere des Sterns ausgefüllt ist und
\lstinline{"blue"} ist die Farbe. Statt \lstinline{"solid"} kannst Du auch
\lstinline{"outline"} schreiben, dann wird auch etwas klarer, was
"<überspringen"> heißt:
%
% filename can't contain hyphen because of alltt
\begin{lstlisting}
(star-polygon 20 10 3 "outline" "blue")
|\evalsto| |\includegraphics[height=24pt]{elemente/starpolygon_outline}|
\end{lstlisting}
%
\begin{aufgabeinline}
Wofür stehen die Zahleneingaben bei \lstinline{square} und
\lstinline{circle}? Probiere unterschiedliche Zahlen aus! Es gibt
auch eine eingebaute Funktion \lstinline{rectangle}. Kannst Du ein
funktionierendes Beispiel für den Einsatz von \lstinline{rectangle}
konstruieren? Außerdem gibt es eine eingebaute Funktion
\lstinline{ellipse}, die genauso benutzt wird wie \lstinline{rectangle}~--
probiere sie aus!
\end{aufgabeinline}
%
Bilder sind Werte wie Zahlen und Zeichenketten auch. Du kannst
mit Definitionen auch Namen dafür vergeben:
%
\begin{lstlisting}
(define s1 (square 40 "solid" "red"))
(define c1 (circle 40 "solid" "green"))
(define p1 (star-polygon 20 10 3 "solid" "blue"))
\end{lstlisting}
%
\begin{aufgabeinline}
Probiere diese Definitionen in der REPL aus, indem Du dort
\lstinline{s1}, \lstinline{c1} und \lstinline{p1} eingibst. Was
passiert, wenn Du \lstinline{(s1)} eingibst? Warum?
\end{aufgabeinline}
\begin{aufgabeinline}
Du kannst auch Bilddateien oder Bilder von Webseiten in Dein Programm
einfügen, wie in einem Textverarbeitungsprogramm. Das geht so:
%
\begin{itemize}
\item Um eine Bilddatei einzufügen, wähle den Menüpunkt
\texttt{Einfügen $\rightarrow$ Bild einfügen} beziehungsweise
\texttt{Insert $\rightarrow$ Insert Image}.
\item Um ein Bild aus einer Webseite einzufügen, wähle aus dem
Kontextmenü im Browser \texttt{Bild kopieren} (oder \texttt{Copy
Image} oder so ähnlich) aus. Du kannst das Bild dann in
DrRacket über den Menüpunkt \texttt{Bearbeiten $\rightarrow$ Einfügen}
beziehungsweise \texttt{Edit $\rightarrow$ Paste} einfügen.
\end{itemize}
%
Probier es aus und
gib dem Bild einen Namen!
\end{aufgabeinline}
%
Mit Bildern kann DrRacket auch rechnen:\label{function:beside-above}
%
\begin{lstlisting}
(beside s1 p1)
|\evalsto| |\includegraphics[height=24pt]{elemente/beside.png}|
(above s1 c1)
|\evalsto| |\includegraphics[width=24pt]{elemente/above.png}|
(above (beside s1 p1) (beside p1 c1))
|\evalsto| |\includegraphics[width=48pt]{elemente/abovebeside.png}|
\end{lstlisting}
%
\begin{aufgabeinline}
Probiere in der REPL folgende Ausdrücke aus:
\begin{lstlisting}
(triangle 50 "outline" "red")
(square 100 "solid" "blue")
\end{lstlisting}
%
Schreibe mit Hilfe der Funktionen \lstinline{triangle} und
\lstinline{square} einen Ausdruck, der ein ganz einfaches Haus
berechnet.
\end{aufgabeinline}
%
Das heißt, \lstinline{above} akzeptiert als Eingabe zwei (oder mehr)
Bilder und macht daraus wieder ein Bild, in dem die Teilbilder
übereinander stehen. Das gleiche gilt für \lstinline{beside}, nur dass
die Bilder nebeneinander angeordnet werden. Selbstverständlich können
\lstinline{above} und \lstinline{beside} auch kombiniert werden.
\section{Abstraktion und Applikation}
\label{sec:abstraktion-und-applikation}
\mentioncode{elemente/tile.rkt}
%
Hier sind zwei Ausdrücke, welche die Bilder aus dem vorigen Abschnitt
zu einem Muster kombinieren:
%
\begin{lstlisting}
(above
(beside s1 p1)
(beside p1 s1))
|\evalsto| |\includegraphics[width=48pt]{elemente/tile1}|
(above
(beside p1 c1)
(beside c1 p1))
|\evalsto| |\includegraphics[width=48pt]{elemente/tile2}|
\end{lstlisting}
%
Beide Ausdrücke folgen dem gleichen Muster, sie "<kacheln"> jeweils zwei
Bilder in einer quadratischen Anordnung. Das Muster könnte man so
hinschreiben:
%
\begin{lstlisting}
(above
(beside a b)
(beside b a))
\end{lstlisting}
%
Das erste Beispiel entsteht, indem für \lstinline{a} \lstinline{s1}
eingesetzt wird und für \lstinline{b} \lstinline{p1}, im zweiten für \lstinline{a}
\lstinline{p1} und für \lstinline{b} dann \lstinline{c1}.
Dieses Muster kannst Du in ein Programm gießen. Dann müssen wir nicht
jedesmal \lstinline{above} ~\ldots~ \lstinline{beside} ~\ldots~ \lstinline{beside} eintippen.
Dazu schreibst Du es erst einmal genauso hin, also mit \lstinline{a} und
\lstinline{b}. Wenn es startet, erscheint folgende Meldung:
%
\begin{alltt}
\color{red}a: Variable ist nicht definiert
\end{alltt}
%
Das bedeutet, dass es keine Definition für \lstinline{a} gibt.
Du könntest eine hinschreiben, zum Beispiel:
%
\begin{lstlisting}
(define a s1)
\end{lstlisting}
%
Aber dann wäre \lstinline{a} auf \lstinline{s1} festgelegt. Wir wollen
stattdessen das Muster verallgemeinern, so dass Du es mehrmals mit
unterschiedlichen Werten für \lstinline{a} und \lstinline{b} verwenden
kannst. Dieser Verallgemeinerungsprozess heißt beim Programmieren
\textit{Abstraktion\index{Abstraktion}}. Dafür müssen wir dem Muster
noch etwas hinzufügen, um zu sagen, dass wir unterschiedliche Werte
für \lstinline{a} und \lstinline{b} einsetzen wollen:
%
\begin{lstlisting}
(lambda (a b)
(above
(beside a b)
(beside b a)))
\end{lstlisting}
%
Das \lstinline{lambda}\indexvariable{lambda} ist eine Art Zauberwort, es sagt soviel wie: "<Für
die Variablen \lstinline{a} und \lstinline{b} möchte ich später (und
vielleicht mehrmals) Werte einsetzen."> Wenn Du das Programm jetzt
startest, geht die Fehlermeldung weg und in der REPL erscheint:
%
\begin{lstlisting}
#<function>
\end{lstlisting}
%
Das deutet darauf hin, dass bei dem \lstinline{lambda} eine Funktion
herauskommt. Um etwas damit anzufangen, gib ihr einen Namen mit
\lstinline{define}:
%
\indexvariable{tile}
\begin{lstlisting}
(define tile
(lambda (a b)
(above
(beside a b)
(beside b a))))
\end{lstlisting}
%
(Alles schön richtig einrücken! "<To tile"> heißt auf Deutsch
"<kacheln">.\footnote{Wir mögen gern englischsprachige Namen für
Variablen. Das ist aber eine rein persönliche Präferenz~-- gern
kannst Du deutschsprachige Variablen für Deine eigenen Programme
verwenden.})
Dadurch ist eine neue Operation entstanden. Die kannst Du direkt
verwenden:
%
\begin{lstlisting}
(tile s1 p1)
|\evalsto| |\includegraphics[width=48pt]{elemente/tile1}|
(tile p1 c1)
|\evalsto| |\includegraphics[width=48pt]{elemente/tile2}|
\end{lstlisting}
%
Was ist da passiert? Am einfachsten kann man das in einem speziellen
Werkzeug sehen, dem \textit{Stepper\index{Stepper}}. Um ihn zum
Einsatz zu bringen, stelle sicher, dass im Definitionsfenster folgendes
Programm steht:
%
\begin{lstlisting}
(define s1 (square 40 "solid" "red"))
(define c1 (circle 40 "solid" "green"))
(define p1 (star-polygon 20 10 3 "solid" "blue"))
(define tile
(lambda (a b)
(above
(beside a b)
(beside b a))))
(tile s1 p1)
(tile p1 c1)
\end{lstlisting}
%
Dann drück auf den \texttt{Stepper}-Knopf (beziehungsweise
\texttt{Step} in der englischen Fassung) oben rechts im
DrRacket-Fenster. Es erscheint ein neues Fenster, das so aussieht:
\begin{figure}[H]
\centering
\includegraphics[width=0.6\textwidth]{elemente/stepper-0}
\caption{Der Stepper in Aktion}
\label{fig:stepper-0}
\end{figure}
%
\noindent Wenn Du jetzt den Knopf mit dem Vorwärts- beziehungsweise
dem Rückwärts-Pfeil drückst, kannst Du zusehen, wie DrRacket Dein
Programm ausführt. Wenn Du ein paar Schritte vorwärts gehst, sieht
das so aus:
%
\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{elemente/stepper-1}
\caption{Stepper: Variable ersetzen}
\label{fig:stepper-1}
\end{figure}
%
\noindent Du kannst sehen, wie DrRacket jeweils einen Schritt auf
einmal auswertet~-- der ist auf der linken Seite grün~-- und dann
rechts durch das Resultat ersetzt. Oben kannst Du sehen, wie der
Stepper die Variable \lstinline{tile} durch den \lstinline{lambda}-Ausdruck
aus der Definition von \lstinline{tile} ersetzt. Das macht der Stepper
auch mit den Definitionen von \lstinline{s1} und \lstinline{p1}:
%
\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{elemente/stepper-2}
\caption{Stepper: Variable}
\label{fig:stepper-2}
\end{figure}
%
\noindent Interessant wird es danach. Die Variablen aus den Definitionen sind
alle ersetzt. Hinter dem \lstinline{lambda}-Ausdruck stehen jetzt das
Quadrat und der Stern, und die werden jetzt für die Variablen aus dem
\lstinline{lambda}-Ausdruck eingesetzt, also das Quadrat für \lstinline{a}
und der Stern für \lstinline{b}:
%
\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{elemente/stepper-3}
\caption{Stepper: Applikation}
\label{fig:stepper-3}
\end{figure}
%
\noindent Dabei verschwindet auch das \lstinline{lambda}.
%
\begin{aufgabeinline}
Probiere das Beispiel im Stepper aus und klicke Dich bis zum Ende
durch. Mache Dir dabei klar, wie jeweils die linke mit der rechten
Seite zusammenhängt.
\end{aufgabeinline}
%
\lstinline{(tile s1 p1)} ist eine sogenannte
\textit{Applikation\index{Applikation}}: ein Ausdruck mit
Klammern drum. Der Operator und die Operanden der
Applikation sind ebenfalls Ausdrücke. Der Operator ergibt eine
Funktion~-- entweder eingebaut oder aus einem
\lstinline{lambda}-Ausdruck. Eine Applikation wird auch oft
\textit{Funktionsaufruf\index{Funktionsaufruf}} oder
\textit{Funktionsanwendung\index{Funktionsanwendung}} genannt.
Wenn die Funktion ein \lstinline{lambda}-Ausdruck ist wie in
Abbildung~\ref{fig:stepper-3}, dann muss es genauso viele Operanden
geben wie der \lstinline{lambda}-Ausdruck Variablen hat.
Dann wertet DrRacket den Ausdruck wie folgt aus:
%
\begin{enumerate}
\item Die Operanden werden ausgewertet und ergeben die Eingaben für
die Funktion, die sogenannten
\textit{Argumente\index{Argument}}.\label{sec:argument}
\item Die Argumente werden für die
Variablen des \lstinline{lambda}-Ausdrucks~-- die sogenannten
\textit{Parameter\index{Parameter}}~-- im Innenteil des
\lstinline{lambda}-Ausdrucks, dem \textit{Rumpf\index{Rumpf}}
eingesetzt.
\end{enumerate}
%
\begin{feature}{Abstraktion und Applikation}{scheme:abstraction}
Eine Abstraktion\index{Abstraktion} hat folgende Form:
\begin{lstlisting}
(lambda ($p\sb{1} \ldots p\sb{n}$) $e$)
\end{lstlisting}
%
Die $p_i$ sind jeweils Namen, die \textit{Parameter}\index{Parameter}, und
$e$ ist der \textit{Rumpf}\index{Rumpf}. In $e$ dürfen die $p_i$
vorkommen. Der Wert einer Abstraktion ist eine \textit{Funktion}\index{Funktion},
welche für jeden Parameter eine Eingabe erwartet.
Eine \textit{Applikation} einer Funktion hat folgende Form:
%
\begin{lstlisting}
($f$ $a\sb{1}$ $\ldots$ $a\sb{n}$)
\end{lstlisting}
%
$f$ ist ein Ausdruck, der eine Funktion ergeben muss, die $a_i$ sind
ebenfalls Ausdrücke, die \textit{Argumente}\index{Argument}. Bei
der Auswertung einer Applikation werden zunächst $f$ und die $a_i$
ausgewertet; danach geht es mit der Auswertung des Rumpfes der
Funktion weiter, wobei für die Parameter $p_i$ jeweils die Werte der
Argumente $a_i$ eingesetzt werden.
\end{feature}
%
\lstinline{Lambda}-Ausdrücke heißen auch
\textit{Abstraktionen\index{Abstraktion}}.
Abbildung~\ref{scheme:abstraction} fasst zusammen, wie Abstraktionen
und Applikationen aufgebaut sind und ausgewertet werden.
Verwirrend ist vielleicht der Unterschied zwischen Abstraktion und
Funktion: Die Abstraktion ist der \lstinline{lambda}-Ausdruck im
Programm, die Funktion ist der Wert, der bei der Programmauswertung
dabei herauskommt. Wir verwenden im Buch aber häufig den Begriff
"<Funktion"> für eine Abstraktion, weil uns interessiert, was bei der
Abstraktion herauskommt.
\begin{aufgabeinline}
Kannst Du das Ergebnis einer Applikation von
\lstinline{tile} wieder als Eingabe für ein erneutes
\lstinline{tile} benutzen? Probier es aus!
\end{aufgabeinline}
\section{Information und Daten}
\label{sec:information-daten}
Eine Definition wie
%
\begin{lstlisting}
(define mehrwertsteuer 19)
\end{lstlisting}
%
suggeriert, dass die Zahl 19 an dieser Stelle eine Bedeutung "<in der
realen Welt"> hat, zum Beispiel in einem Programm, das eine Registrierkasse
steuert oder das bei der Steuererklärung hilft. Die Bedeutung könnte
folgende Aussage sein: "<Der Mehrwertsteuersatz beträgt 19\%.">
Dieser Satz repräsentiert \textit{Information}\index{Information},
also einen Fakt über die Welt oder zumindest den Ausschnitt der Welt, in
dem das Programm arbeiten soll. In Computerprogrammen wird
Information in eine vereinfachte Form gebracht, mit der das Programm
rechnen kann~-- in diesem Fall die Zahl 19. Diese vereinfachte Form
heißt \textit{Daten}\index{Daten}: Daten sind
\textit{Repräsentationen}\index{Repräsentation} für Information.
Eine der wichtigsten Aufgaben beim Programmieren ist, die richtige
Form für die Daten zu wählen, um die für das Programm relevanten
Informationen darzustellen und die Informationen dann in Daten zu
übersetzen.
Nicht immer ist offensichtlich, welche Information durch bestimmte
Daten repräsentiert werden. Die Zahl 23 zum Beispiel könnte eine Reihe
von Informationen darstellen:
%
\begin{itemize}
\item die Anzahl der Haare von Bruce Willis
\item die aktuelle Außentemperatur in °C in Tübingen
\item die maximale Außentemperatur vom 1.7.2000 in °C in Tübingen
\item die Größe in m$^2$ des Schlafzimmers
\item die Rückennummer von Alexandra Popp
\end{itemize}
%
Welche gemeint ist, hängt vom Kontext ab. Damit andere unsere
Programme lesen können, werden wir also immer wieder klarstellen
müssen, was der Kontext ist und wie Information in Daten zu übersetzen
ist und umgekehrt. An konkreten Beispielen können (und sollten) wir
dazu einen Kommentar anbringen:
%
\begin{lstlisting}
(define bruce-willis 23) ; Anzahl der Haare
(define temperatur-tübingen 23) ; 23|\si{\degree}|C in Tübingen
(define temperatur-tübingen-2000-07-01 23)
; 23|\si{\degree}|C in Tübingen am 7.1.2000
(define schlafzimmer 23) ; Schlafzimmer ist 23m$^2$
(define alexandra-popp 23) ; Rückennummer
\end{lstlisting}
%
\begin{feature}{Kommentare}{scheme:comment}
Ein Semikolon \lstinline{;} kennzeichnet einen
\textit{Kommentar\index{Kommentar}}. Der Kommentar erstreckt sich
vom Semikolon bis zum Ende der Zeile und wird von DrRacket
ignoriert.
\end{feature}
%
Das Semikolon kennzeichnet den Rest Zeile als
\textit{Kommentar\index{Kommentar}}. DrRacket ignoriert diese Zeile
beim Auswerten, aber für menschliche Leserinnen ist sie nützlich.
Abbildung~\ref{scheme:comment} fasst zusammen, wie das Semikolon
funktioniert.
\section{Programme systematisch konstruieren}
\mentioncode{elemente/stromtarif.rkt}
%
In Abschnitt~\ref{sec:abstraktion-und-applikation} haben wir gezeigt,
wie Abstraktion und Applikation bei der Programmauswertung
funktionieren. Das Verständnis dafür ist wichtig, aber Du musst beim
Schreiben Deines Programms nicht die ganze Zeit daran denken, wie
DrRacket Dein Programm auswertet. Entsprechend kümmern wir uns in
diesem Buch hauptsächlich darum, wie Du Programme systematisch
konstruierst.
Schauen wir uns das anhand einer kleinen aber realistischen Aufgabe an:
\smallskip
\noindent Betrachte folgende Stromtarife. Beide Tarife
bestehen aus einer monatlichen Grundgebühr und einem Teil, der sich
nach den verbrauchten Kilowattstunden (kWh) richtet.
%
\begin{center}
\begin{tabular}{l|c|c|}
& Grundgebühr pro Monat & Verbrauchspreis pro kWh \\
\hline
Tarif "<Billig-Strom"> & \EUR{4,90} & \EUR{0,19} \\
\hline
Tarif "<Watt für wenig"> & \EUR{8,20} & \EUR{0,16} \\
\hline
\end{tabular}
\end{center}
\begin{enumerate}
\item Schreibe ein Programm, das den Monatsverbrauch in
Kilowattstunden akzeptiert und den im Tarif "<Billig-Strom"> zu
zahlenden monatlichen Rechnungsbetrag berechnet.
\item Schreibe ein Programm, das den Monatsverbrauch in
Kilowattstunden akzeptiert und den im Tarif "<Watt für wenig"> zu
zahlenden monatlichen Rechnungsbetrag
berechnet.
\end{enumerate}
%
Fangen wir mit dem ersten Aufgabenteil an!
\paragraph{Funktion}
Zunächst einmal: Da steht "<Schreibe ein Programm~\ldots">. In den
Lehrsprachen dieses Buchs heißt das immer "<Schreibe eine
\emph{Funktion}~\ldots">. Später werden wir Programme schreiben, die
neben der "<Hauptfunktion"> noch "<Hilfsfunktionen"> haben, aber das
Prinzip bleibt immer das gleiche.
Wenn dort steht, "<das den Monatsverbrauch in Kilowattstunden
akzeptiert">, dann bedeutet dies, dass die Funktion den
Monatsverbraucht als Eingabe akzeptieren soll~-- also als Argument.
Ebenso bedeutet "<und den \ldots{} zu zahlenden monatlichen
Rechnungsbetrag berechnet">, dass die Funktion diesen Rechungsbetrag
als Ergebnis liefern soll.
\paragraph{Gerüst}
Funktionen, die ein Problem aus einer Aufgabenstellung lösen, sollten immer
einen Namen haben~-- den sollten wir uns gleich am Anfang ausdenken. Der Name
\lstinline{billig-strom} bietet sich an. Wir wissen schon, dass die Funktion
den Verbrauch in Kilowattstunden akzeptiert. Wenn wir uns für Kilowattstunden
auch noch einen Namen ausdenken, können wir direkt ein unfertiges Programm
hinschreiben, ohne groß nachzudenken:
%
\begin{lstlisting}
(define billig-strom
(lambda (kWh)
...))
\end{lstlisting}
%
\emph{Wichtig:} Schreibe dieses \textit{Gerüst\index{Gerüst}}
unbedingt hin, auch wenn Du noch keine Vorstellung hast, wie es danach
weitergeht. Immer. Jedes Mal.
\paragraph{Rumpf}
Für das Berechnen des Rechnungsbetrags können wir eine Formel
aufschreiben: Er ist die Summe aus der Grundgebühr und
dem Produkt aus Energie (in Kilowattstunden) und dem Preis einer Kilowattstunde.
Entsprechend müssen wir den Rumpf\index{Rumpf} der
Funktion ergänzen:\index[definitions]{billig-strom}
%
\begin{lstlisting}
(define billig-strom
(lambda (kWh)
(+ 4.90 (* 0.19 kWh))))
\end{lstlisting}
%
Die Funktion \lstinline{billig-strom} kannst Du jetzt aufrufen:
%