Grundlagen der funktionsorientierten Programmierung mit SCHEME/Prozeduren
Aus ProgrammingWiki
Wiki-Quelltext dieser Seite.
<language>Scheme</language>
== Definition von Prozeduren ==
Um Kreisflächen beliebiger Radien zu bestimmen, war bisher immer die Neudefinition des Radiuses notwendig.<br />
Wie kann der Radius als ''Argument'' übergeben werden?
'''Lösungsidee:'''
Definiere eine ''Prozedur'', die ähnlich einer mathematischen Funktion einen Funktionswert zurückgibt.
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<th align="left" valign="top">Mathematik:</th>
<td>
<math>flaeche: r \longrightarrow \pi \cdot r^2</math><br />
oder:<br />
<math>flaeche(r) = \pi \cdot r^2</math><br />
</td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<th align="left" valign="top">Funktionsorientierte Programmierung:</th>
<td>
[[Bild:Flaechenberechnung.gif]]
</td>
</tr>
</table>
'''Implementation:'''
<code id="4c72e4c772284">
(define pi (* 4 (atan 1)))
(define flaeche
(lambda (r)
(* pi r r)))
</code>
Wir überzeugen uns zunächst davon, dass wir tatsächlich eine Prozedur definiert haben:
<eval id="4c72e4c7723b0">
flaeche
</eval>
Nun können wir Berechnungen mit beliebigen Radien vornehmen:
<eval id="4c72e4c7724d2">
(flaeche 10)
</eval>
'''Interpretation:'''<br />
* Die Prozedur <tt>(lambda (r) (* pi r r))</tt> wird an den Namen <tt>flaeche</tt> gebunden.
* Der Parameter <tt>r</tt> heißt ''gebundene'' Variable.
* Die Variablen <tt>*</tt> und <tt>pi</tt> sind dagegen ''ungebunden'' oder ''frei''.
'''Beachte:'''<br />
Die Bindung einer Prozedur an einen Namen heißt ''Prozedurabstraktion''. Sie ist aber nicht notwendig!<br />
In Scheme können auch ''unbenannte'' Prozeduren verwendet werden:
<eval id="4c72e4c7725db">
(lambda (x) (* x x))
</eval>
<eval id="4c72e4c7726ec">
((lambda (x) (* x x)) 12)
</eval>
=== Zusammenfassung ===
* Benutzerdefinierte Prozeduren werden mit ''λ-Ausdrücken'' definiert.
* Allgemeine Syntax: <tt>(lambda (<Parameter>) <Body>)</tt>.
* Die Anzahl der Parameter kennzeichnet die ''Stelligkeit'' einer Prozedur. Ist die Parameterliste leer, spricht man von ''nullstelligen'' Prozeduren,
* Die Parameter sind gebundene Variablen, die beliebig bezeichnet werden können, sofern sie nicht mit freien Variablen im Körper übereinstimmen.
* λ-Ausdrücke können an Prozedurnamen gebunden werden (''Prozedurabstraktion'').
== Aufgaben ==
<code id="4c7eb87d68027" hidden>
(define eps 1e-03)
(define sqr
(lambda (x)
(* x x)))
(define test-runden
(lambda (x anzahl)
(/ (round (* x (expt 10 anzahl))) (expt 10 anzahl))))
(define test-flaeche
(lambda (radius)
(* pi radius radius)))
(define test-volumen-vollzylinder
(lambda (radius hoehe)
(* (test-flaeche radius) hoehe)))
(define test-volumen-hohlzylinder
(lambda (radius1 radius2 hoehe)
(- (test-volumen-vollzylinder radius1 hoehe) (test-volumen-vollzylinder radius2 hoehe))))
(define test-volumen-quadpyramide
(lambda (seite hoehe)
(* 1/3 seite seite hoehe)))
(define test-oberflaeche-quadpyramide
(lambda (seite hoehe)
(* seite (+ seite (* 2 (sqrt (+ (sqr (/ seite 2)) (sqr hoehe))))))))
(define test-volumen-quadpyramidenstumpf
(lambda (seite hoehe stumpfhoehe)
(- (test-volumen-quadpyramide seite hoehe)
(test-volumen-quadpyramide (* (- 1 (/ stumpfhoehe hoehe)) seite) (- hoehe stumpfhoehe)))))
(define test-oberflaeche-quadpyramidenstumpf
(lambda (seite hoehe stumpfhoehe)
(- (test-oberflaeche-quadpyramide seite hoehe)
(test-oberflaeche-quadpyramide
(* (- 1 (/ stumpfhoehe hoehe)) seite) (- hoehe stumpfhoehe))
(* -2 (sqr (* (- 1 (/ stumpfhoehe hoehe)) seite))))))
</code>
<ol>
<li>
=== Sinnvolles Runden ===
Für alle nachfolgenden Berechnungen ist es sinnvoll, über eine Prozedur zu verfügen, die auf eine ''beliebige'' Anzahl von Nachkommastellen rundet.<br />
'''Beispiele:'''
<pre>
(runden 12.3456 2) --> 12.35
(runden 0.005712 3) --> 0.006
</pre>
Nutzen Sie zur Implementation die Standard-Prozedur <tt>round</tt>, die lediglich ganzzahlig rundet.
<code id="4c7eb87d6815d">
(define runden
(lambda (x anzahl)
...))
</code>
<check>
(and (= (runden 12.3456 2) 12.35) (= (runden 0.005712 3) 0.006))
</check>
<eval id="4c7eb87d682c5">
(runden 12.3456 2)
</eval>
</li>
<li>
=== Vollzylinder ===
Schreiben Sie eine Prozedur zur Volumenberechnung eines geraden Vollzylinders.
<code id="4c736c6335cf3">
(define volumen-vollzylinder
(lambda (radius hoehe)
...))
</code>
<check>
(< (- (volumen-vollzylinder 13 55) (test-volumen-vollzylinder 13 55)) eps)
</check>
<eval id="4c736c6335f54">
(volumen-vollzylinder 7 28)
</eval>
</li>
<li>
=== Hohlzylinder ===
Implementieren Sie nun eine Prozedur zur Volumenberechnung eines geraden Hohlzylinders.
<code id="4c736c6335e13">
(define volumen-hohlzylinder
(lambda (radius1 radius2 hoehe)
...))
</code>
<check>
(< (- (volumen-hohlzylinder 13 7 55) (test-volumen-hohlzylinder 13 7 55)) eps)
</check>
<eval id="4c7eb922c0443">
(volumen-hohlzylinder 7 6 28)
</eval>
</li>
<li>
=== Pyramide und Pyramidenstumpf ===
Definieren Sie zunächst die Prozedur zur Berechnung des Volumens und der Oberfläche gerader quadratischer Pyramiden.
<code id="4c7540a6484bf">
(define volumen-quadpyramide
(lambda (seite hoehe)
...))
</code>
<check>
(< (- (volumen-quadpyramide 5.5 17.5) (test-volumen-quadpyramide 5.5 17.5)) eps)
</check>
<eval id="4c7eb922c058d">
(volumen-quadpyramide 5.5 17.5)
</eval>
<code id="4c7c9a3f2101a">
(define oberflaeche-quadpyramide
(lambda (seite hoehe)
...))
</code>
<check>
(< (- (oberflaeche-quadpyramide 5.5 17.5) (test-oberflaeche-quadpyramide 5.5 17.5)) eps)
</check>
<eval id="4c7eb922c06c1">
(oberflaeche-quadpyramide 5.5 17.5)
</eval>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="250" align="center">
[[Bild:Pyramide1.gif]]
</td>
<td width="350" valign="top">
In einer nun geringeren Höhe wird die Spitze der quadratischen Pyramide abgeschnitten.<br />
Zurück bleibt ein Pyramidenstumpf.<br />
Schreiben Sie eine Prozedur, die entsprechend dieser Vorstellung das Volumen des Pyramidenstumpfes ermittelt.
</td>
</tr>
</table>
<code id="4c754364265d2">
(define volumen-quadpyramidenstumpf
(lambda (seite hoehe stumpfhoehe)
...))
</code>
<check>
(< (- (volumen-quadpyramidenstumpf 5.5 17.5 9.0) (test-volumen-quadpyramidenstumpf 5.5 17.5 9.0)) eps)
</check>
<eval id="4c7eb922c07fd">
(volumen-quadpyramidenstumpf 5.5 17.5 9.0)
</eval>
<code id="4c7c9a3f21150">
(define oberflaeche-quadpyramidenstumpf
(lambda (seite hoehe stumpfhoehe)
...))
</code>
<check>
(< (- (oberflaeche-quadpyramidenstumpf 5.5 17.5 9.0) (test-oberflaeche-quadpyramidenstumpf 5.5 17.5 9.0)) eps)
</check>
<eval id="4c7eb922c0937">
(oberflaeche-quadpyramidenstumpf 5.5 17.5 9.0)
</eval>
</li>
</ol>