Grundlagen der funktionsorientierten Programmierung mit SCHEME/Prozeduren

Aus ProgrammingWiki

Wiki-Quelltext dieser Seite.

<language>SchemeJS</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>
$flaeche: r \longrightarrow \pi \cdot r^2$<br />
oder:<br />
$flaeche(r) = \pi \cdot r^2$<br />
</td>
</tr>
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<th align="left" valign="top">Funktionsorientierte Programmierung:</th>
<td>
[[Bild:Flaechenberechnung.gif]]
</td>
</tr>
</table>

'''Implementation:'''

<code id="59170ccdd38c6">
(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:

<run id="4c72e4c7723b0">
flaeche
</run>

Nun können wir Berechnungen mit beliebigen Radien vornehmen:

<run id="4c72e4c7724d2">
(flaeche 10)
</run>

'''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:

<run id="4c72e4c7725db">
(lambda (x) (* x x))
</run>

<run id="4c72e4c7726ec">
((lambda (x) (* x x)) 12)
</run>

=== Zusammenfassung ===

* Benutzerdefinierte Prozeduren werden mit ''&lambda;-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.
* &lambda;-Ausdrücke können an Prozedurnamen gebunden werden (''Prozedurabstraktion'').

== Aufgaben ==

<code id="5ba12492e1f7d" hidden>
(define eps 1e-06)

(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))))))

(define test-umfang-n-eck
  (lambda (r n)
    (* n (sqrt (* 2 r r (- 1 (cos (/ (* 2 pi) n))))))))

(define test-flaeche-n-eck
  (lambda (r n)
    (let ([a (sqrt (* 2 r r (- 1 (cos (/ (* 2 pi) n)))))]
          [h (* r (cos (/ pi n)))])
      (/ (* n a h) 2))))
</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) (= (runden 12.3456 2) 12.35) (= (runden 0.005712 3) 0.006))
</check>

<run id="4c7eb87d682c5">
(runden 12.3456 2)
</run>
</li>
<li>

=== Vollzylinder ===

Schreiben Sie eine Prozedur zur Volumenberechnung eines geraden Vollzylinders.

<code id="4c736c6335cf3">
(define volumen-vollzylinder
  (lambda (radius hoehe)
    ...))
</code>

<check>
(and (volumen-vollzylinder 13 55) (< (abs (- (volumen-vollzylinder 13 55) (test-volumen-vollzylinder 13 55))) eps))
</check>

<run id="4c736c6335f54">
(volumen-vollzylinder 7 28)
</run>
</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>
(and (volumen-hohlzylinder 13 7 55) (< (abs (- (volumen-hohlzylinder 13 7 55) (test-volumen-hohlzylinder 13 7 55))) eps))
</check>

<run id="4c7eb922c0443">
(volumen-hohlzylinder 7 6 28)
</run>
</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>
(and (volumen-quadpyramide 5.5 17.5) (< (abs (- (volumen-quadpyramide 5.5 17.5) (test-volumen-quadpyramide 5.5 17.5))) eps))
</check>

<run id="4c7eb922c058d">
(volumen-quadpyramide 5.5 17.5)
</run>

<code id="4c7c9a3f2101a">
(define oberflaeche-quadpyramide
  (lambda (seite hoehe)
    ...))
</code>

<check>
(and (oberflaeche-quadpyramide 5.5 17.5) (< (abs (- (oberflaeche-quadpyramide 5.5 17.5) (test-oberflaeche-quadpyramide 5.5 17.5))) eps))
</check>

<run id="4c7eb922c06c1">
(oberflaeche-quadpyramide 5.5 17.5)
</run>

<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="250" align="center">
[[Bild:Pyramide1.gif]]
</td>
<td width="450" valign="center">
In einer nun geringeren Höhe wird die Spitze der quadratischen Pyramide abgeschnitten.<br />
Zurück bleibt ein Pyramidenstumpf.<br />
Schreiben Sie zwei Prozeduren, die entsprechend dieser Vorstellung das Volumen und den Oberflächeninhalt des Pyramidenstumpfes ermitteln.
</td>
</tr>
</table>

<code id="4c754364265d2">
(define volumen-quadpyramidenstumpf
  (lambda (seite hoehe stumpfhoehe)    
    ...))
</code>

<check>
(and (volumen-quadpyramidenstumpf 5.5 17.5 9.0) (< (abs (- (volumen-quadpyramidenstumpf 5.5 17.5 9.0) (test-volumen-quadpyramidenstumpf 5.5 17.5 9.0))) eps))
</check>

<run id="4c7eb922c07fd">
(volumen-quadpyramidenstumpf 5.5 17.5 9.0)
</run>

<code id="4c7c9a3f21150">
(define oberflaeche-quadpyramidenstumpf
  (lambda (seite hoehe stumpfhoehe)    
    ...))
</code>

<check>
(and (oberflaeche-quadpyramidenstumpf 5.5 17.5 9.0) (< (abs (- (oberflaeche-quadpyramidenstumpf 5.5 17.5 9.0) (test-oberflaeche-quadpyramidenstumpf 5.5 17.5 9.0))) eps))
</check>

<run id="4c7eb922c0937">
(oberflaeche-quadpyramidenstumpf 5.5 17.5 9.0)
</run>
</li>
<li>
=== Regelmäßiges N-Eck ===

<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="250" align="center">
[[Bild:N_Eck1.gif]]
</td>
<td width="450" valign="center">
Zu einem regelmäßigen N-Eck sind der Außenradius $r$ und die Eckenzahl $N \geq 3$ gegeben.<br />
Implementieren Sie zwei Prozeduren zur Berechnung des Umfangs und des Flächeninhalts dieses N-Ecks.
</td>
</tr>
</table>

<code id="5eef291e3f900">
(define umfang-n-eck
  (lambda (r n)    
    ...))
</code>

<check>
(and (umfang-n-eck 5.5 7) (< (abs (- (umfang-n-eck 5.5 7) (test-umfang-n-eck 5.5 7))) eps))
</check>

<run id="5eef291e3fa93">
(umfang-n-eck 5.5 7)
</run>

<code id="5eef291e3f99a">
(define flaeche-n-eck
  (lambda (r n)    
    ...))
</code>

<check>
(and (flaeche-n-eck 5.5 7) (< (abs (- (flaeche-n-eck 5.5 7) (test-flaeche-n-eck 5.5 7))) eps))
</check>

<run id="5eef291e3fb2c">
(flaeche-n-eck 5.5 7)
</run>
</li>
</ol>