Designfragen für Schleifen:
for p in 1 .. 10 loop .. end loop;
map (\x -> x*x) [1,2,3] ==> [1,4,9] Collection<String> c = new LinkedList<String> (); for (String s : c) { ... }
while ( x > 0 ) { if ( ... ) { x = ... } ... }
Idee: vor Beginn steht Anzahl der Durchläufe fest.
richtig realisiert ist das nur in Ada:
for p in 1 .. 10 loop ... end loop;
p
wird implizit deklariert
Vergleiche (beide Punkte) mit Java, C++, C
Satz: Jedes Programm aus
Äquivalenter Begriff (für Bäume anstatt Zahlen):
strukturelle Induktion (fold, Visitor, primitive
Rekursion)
Satz: es gibt berechenbare Funktionen,
die nicht primitiv rekursiv sind.
Beispiel: Interpreter für primitiv rekursive Programme.
Idee: führe für jeden Konstruktor eines algebraischen Datentyps (Liste, Baum) eine Rechnung/Aktion aus.
foreach, Parallel.Foreach,...
So:
interface Iterator<T> { boolean hasNext(); T next (); } interface Iterable<T> { Iterator<T> iterator(); } for (T x : ...) { ... }
Oder so:
public interface IEnumerator<T> : IEnumerator { bool MoveNext(); T Current { get; } } interface IEnumerable<out T> : IEnumerable { IEnumerator<T> GetEnumerator() } foreach (T x in ...) { ... }
(sieben Unterschiede ...)
using System.Collections.Generic; public class it { public static IEnumerable<int> Data () { yield return 3; yield return 1; yield return 4; } public static void Main () { foreach (int i in Data()) { System.Console.WriteLine (i); } } }
das ist die allgemeinste Form, ergibt (partielle) rekursive Funktionen, die terminieren nicht notwendig für alle Argumente.
Steuerung
while (Bedingung) Anweisung
do Anweisung while (Bedingung)
Weitere Änderung des Ablaufes:
operationale Semantik durch Sprünge:
while (B) A; ==> start : if (!B) goto end; A; goto start; end : skip;
(das ist auch die Notation der autotool-Aufgabe)
Ü: do A while (B);
while ( B1 ) { A1; if ( B2 ) break; A2; }
while ( B1 ) { A1; if ( B2 ) continue; A2; }
manche Sprachen gestatten Markierungen (Labels) an Schleifen, auf die man sich in break beziehen kann:
foo : for (int i = ...) { bar : for (int j = ...) { if (...) break foo; } }
Wie könnte man das simulieren?
Satz: zu jedem goto-Programm gibt es ein äquivalentes while-Programm.
Beweis-Idee:
Das nützt aber softwaretechnisch wenig, das übersetzte Programm
ist genauso schwer zu warten wie das Original.
zu jedem while-Programm kann man ein äquivalentes angeben,
das nur Verzweigungen (if) und Unterprogramme benutzt.
Beweis-Idee:
Anwendung: C-Programme ohne Schlüsselwörter.
vereinfachtes Modell,
damit Eigenschaften entscheidbar werden
(sind die Programme P1, P2
Syntax: Programme
Beispiel:
Semantik des Programms P
Satz: Diese Spursprachen
(von goto- und while-Programmen)
sind regulär.
Beweis: Konstruktion über endlichen Automaten.
Damit ist Spur-Äquivalenz von Programmen entscheidbar.
http://www.imn.htwk-leipzig.de/~waldmann/edu/ws13/pps/umfrage/
1 : A1, 2 : A2; .. 5: goto 7; ..
⇒
while (true) {
switch (pc) {
case 1 : A1 ; pc++ ; break; ...
case 5 : pc = 7 ; break; ...
}
}
while (B) A;
⇒
void s () {
if (B) { A; s (); }
}
while (B && !C) { P; if (C) Q; }
Beziehung zu tatsächlicher Äquivalenz?