Konzepte der Programmiersprachen Sommersemester 2012 Torsten Görg 5. Übungsblatt Besprechung am 27. Juni 2012 http://www.iste.uni-stuttgart.de/ps/lehre/ss2012/v-konzepte.html Aufgabe 5.1: Seiteneffekte 1. Welche Eigenschaft muss eine Funktion f in Modula-2 haben, damit in einem Programmstück wie IF f(x) <> f(x) THEN WriteString ("ungleich") ELSE WriteString ("gleich") END; die Meldung ungleich ausgegeben wird? 2. Weshalb ist das Konstrukt y = (x = 2 * x) + (x = x + 1); in C verboten? Probieren Sie aus, ob Ihr Compiler hier Warnungen oder Fehlermeldungen ausgibt, stellen sie dafür möglichst „kleinliches“ Verhalten ein. 3. Seiteneffekte sind nur möglich, wenn es Variablen (oder allgemeiner, Objekte) gibt, die einen veränderbaren Zustand haben. Haben Seiteneffekte und veränderbare Zustände Vorteile oder sollten sie in einer „guten“ Programmiersprache generell verboten sein? Welche Zusammenhänge bestehen mit der funktionalen Programmierung und der objekt-orientierten Programmierung? Aufgabe 5.2: Konzepte funktionaler Sprachen 1. Welche funktionalen Sprachen kennen sie? Welche davon setzen das funktionale Paradigma in einer reinen Form um? Wie und wo werden bei den nicht rein funktionalen Sprachen imperative Sprachmittel eingebaut? 2. Welche Konzepte muss eine rein funktionale Sprache mindestens haben, um Turing-vollständig zu sein? Welche weiteren Konzepte umfassen viele funktionale Sprachen in der Regel darüber hinaus noch? 1 Aufgabe 5.3: Rekursive Funktionen auf rekursiven Datenstrukturen In funktionalen Sprachen führen oft rekursive Funktionen Berechnungen auf rekusiv definierten Datenstrukturen (z.B. Listen) durch. Untersuchen sie folgenden CommonLisp-Programmcode (frei verfügbare CommonLispCompiler und weiterführende Informationen zu CommonLisp erreichen Sie z.B. über http://www.clisp.org/): (01) (02) (03) (04) (05) (06) (07) (08) (09) (10) (11) (12) (13) (14) (15) (16) (17) (defun member (element searchList) (cond ((null searchList) nil) ((eq element (car searchList)) t) (t (member element (cdr searchList))) ) ) (defun mystery (list1 list2) (cond ((null list1) ’()) ((member (car list1) list2) (cons (car list1) (mystery (cdr list1) list2))) (t (mystery (cdr list1) list2)) ) ) Was berechnet die Funktion mystery für zwei als Parameter eingehende Listen list1 und list2 ? 2 Aufgabe 5.4: Funktionale Umsetzung von Algorithmen Gegeben sei folgender Code in der imperativen Programmiersprache Pascal zur Tiefensuche in einem Graphen, die in Form von Adjazenzlisten in adj vorliegt: (01) (02) (03) (04) (05) (06) (07) (08) (09) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) procedure dfs var id, k : integer; val : array[1..maxV] of integer; procedure visit (k : integer) var t : link; begin id:=id+1; val[k]:=id; t:=adj[k]; while t<>nil do begin if val[t^.v]=0 then visit (t^.v); t:=t^.next end end; begin id:=0; for k:=1 to maxV do val[k]:=0; for k:=1 to maxV do if val[k]=0 then visit (k); end; 1. An welchen Stellen dieses Programmfragments werden imperative Sprachmittel verwendet, die so nicht direkt in eine funktionale Lösung übernommen werden können? 2. Formen sie den vorliegenden Code in eine äquivalente funktionale Implementierung um. Benutzen sie dazu eine funktionale Programmiersprache ihrer Wahl (z.B. Haskell). Aufgabe 5.5: List Comprehensions In Haskell können die in einer Liste enthaltenen Werte mit einer Listenabstraktion (engl. list comprehension) ausgedrückt werden, indem man eine Rechenvorschrift angibt, die die Elemente der Liste generiert. Was berechnet die folgende, auf Listenabstraktionen basierende Haskell-Funktion mystery2 für eine als Funktionsparameter übergebene Liste? mystery2 [] = [] mystery2 (h:t) = mystery2 [b | b <- t, b < h] ++ [h] ++ mystery2 [b | b <- t, b > h] 3 Aufgabe 5.6: Typ-Inferenz in funktionalen Sprachen Betrachten Sie folgendes Programmfragment in einer funktionalen Sprache: letrec length = λl. if null l then 0 else 1 + length (tail l) in ... Vorgegeben seien folgende Typen: 0, 1, . . . : int + : int → int → int if/then/else : bool → T → T → T head : T list → T tail : T list → T list null : T list → bool 1. Geben Sie ein äquivalentes Programmfragment für die Definition von length in Haskell-Syntax an. 2. Stellen Sie die Definition von length durch einen Syntaxbaum dar, in dem Sie auch für λ-Abstraktion und Funktionsanwendung jeweils einen Knoten einfügen. Leiten Sie dann für jeden Knoten im Syntaxbaum durch Inferenz den Typ her. Ist die Definition typkorrekt? 3. Ersetzen Sie in der Definition von length den Aufruf von tail durch einen Aufruf von head. Ist diese neue Definition typkorrekt? Falls es einen Unterschied zu Teilaufgabe 2 gibt, wo tritt dieser in der Inferenz auf? 4