Konzepte von Programmiersprachen WS 03/04 http://www-pu.informatik.uni-tuebingen.de/users/klaeren/kvps L ÖSUNG ZU B LATT 2 H. Klaeren, H. Gast (Seite 1 / 4) Aufgabe 1 [4] Syntax, Pragmatik, Semantik 1. "ex1.ml" 1a ≡ let x = 3 in x + y ⇒ Unbound value y "ex2.ml" 1b ≡ 3 + "5" ⇒ This expression has type string but is here used with type int 2. "ex3.ml" 1c ≡ if true then 42 else "Hallo" ⇒ This expression has type string but is here used with type int 3. Beide Ausdrücke haben nach Auswertung den Wert 42, und bei der Anwendung der Funktion passieren keine Seiteneffekte. 4. Syntax Auswahl Programmiersprache, Zeilenumbruch, Einrückungen, Bezeichner Semantik Auswahl der Programmkonstrukte (Schleifen, Funktionsaufrufe, Variablendefinitionen); Auswahl der Algorithmen Pragmatik Welche Unterprogramme führe ich ein? Programmiere ich eher funktional oder imperativ? Wo benutze ich Schnittstellen? Wie allgemein sollen die Funktionen werden? Sollen die Funktionen auch später nocheinmal verwendet werden können oder ist die Anwendung auf das eine Programm beschränkt? Auf welche Funktionalität der Anwendung kann man am ehesten verzichten? Allgemeine Idee: Entscheidungen zwischen mehreren bedeutungsgleichen Optionen. Aufgabe 2 [3] Interpretation vs. Compilation 1. (a) (b) (c) (d) (e) (f) (g) (h) (i) a=4 b=3 c=x d = a+c e=3 f =x g = e+ f h = d ∗g e = a+h 2. Ein Compiler würde entsprechende Maschinenanweisungen generieren, während ein Interpreter genau die Anweisungsfolge von voher auswertet. 3. Ein Compiler könnte erkennen, daß er 3 + x nur einmal auszuwerten braucht und dann gleich das entsprechende Zwischenergebnis zweimal verwenden. 4. Es gibt keine geschachtelten Ausdrücke in der Zielsprache. Konzepte von Programmiersprachen WS 03/04 http://www-pu.informatik.uni-tuebingen.de/users/klaeren/kvps L ÖSUNG ZU B LATT 2 H. Klaeren, H. Gast (Seite 2 / 4) 5. perl benutzt eine virtuelle Maschine und ist demnach eine Compilersprache. Es gibt sogar einen Perl nach C Übersetzer. In perltoc finden sich auch Hinweise auf ”Backends”, ”Bytecode”. Aufgabe 3 [10] Fingerübungen für Funktionen h comp 2a i ≡ let comp : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = fun g f -> fun x -> g (f x);; Macro referenced in 3a. Der Typ bildet das Verhalten von comp nach: Der Rückgabewert von f muß als Eingabe von g zugelassen sein; wenn dies der Fall ist, ist das Resultat eine Funktion, die als Eingabe die Eingaben von f nimmt und als Rückgaben die Rückgaben von g liefert. h compmap 2b i ≡ let compmap : (’a -> ’b) -> (’c -> ’a) -> ’c list -> ’b list = fun g f l -> List.map (comp g f) l;; Macro referenced in 3a. h compmap0 2c i ≡ let compmap’ : (’a -> ’b) -> (’c -> ’a) -> ’c list -> ’b list = fun g f l -> (comp (List.map g) (List.map f)) l;; Macro referenced in 3a. Sei l = [a1 . . . an ] eine beliebige Liste und g, f Funktionen (so daß comp f g definiert ist). Dann ist nach Definition von map compmap g f l = [(g ◦ f )(ai )]ni=1 = [g( f (ai ))]ni=1 = map g[ f (ai ))]ni=1 = map g(map f l) = comp (map g)(map f ) l = compmap’ g f l h bind2 2d i ≡ let bind2 fun f b fun a f a = -> -> b;; Macro referenced in 3a. Hier das Hauptprogramm zum Testen: Konzepte von Programmiersprachen WS 03/04 http://www-pu.informatik.uni-tuebingen.de/users/klaeren/kvps H. Klaeren, H. Gast L ÖSUNG ZU B LATT 2 (Seite 3 / 4) "func.ml" 3a ≡ let prtlist : int list -> unit = fun l -> List.iter (Printf.printf "%d ") l; print_newline ();; (*>>>[*) h comp 2a i h compmap 2b i h compmap0 2c i h bind2 2d i (*<<<]*) let tstcomp = let g=fun x->2*x in let f=fun x->2+x in let h = comp g f and l = [ 3;5;6 ] in Printf.printf "%d\n" (h 5); let r=compmap g f l and r’=compmap’ g f l in (prtlist r); (prtlist r’); if not (r=r’) then print_string "Error: lists not equal\n";; let tstbind = let proj1 = fun a b c d -> a and proj2 = fun a b c d -> b and proj4 = fun a b c d -> d in Printf.printf "1:%d\n" ((bind2 proj1 0) 1 2 3); Printf.printf "2:%d\n" ((bind2 proj2 0) 1 2 3); Printf.printf "4:%d\n" ((bind2 proj4 0) 1 2 3);; Aufgabe 4 [8] Abstrakte Syntaxbäume* Wir beginnen mit dem Hauptprogramm, das die gegebenen Variablenbelegung festhält, die Funktion read_first_arg aufruft, das Ergebnis druckt und schließlich die eval Funktion aufruft. Damit ist Teil (1) bereits erledigt. h Hauptprogramm 3b i ≡ let vars = h Variablenbelegung ? i;; let main : unit = let ast = Arith_rd.read_first_arg () in print_pexp ast; print_newline(); print_int (eval ast vars); print_newline();; Macro referenced in 4b. Die Operatorenliste besteht ist eine Zuordnung der Bezeichner zu Funktionen; glücklicherweise haben die eingebauten Operatoren schon die richtigen Typen: Konzepte von Programmiersprachen WS 03/04 http://www-pu.informatik.uni-tuebingen.de/users/klaeren/kvps L ÖSUNG ZU B LATT 2 H. Klaeren, H. Gast (Seite 4 / 4) h Die Operatorenliste 4a i ≡ let operators : (pid [ (Pid_id("+"), ( (Pid_id("-"), ( (Pid_id("*"), ( ] * + * (int -> int -> int)) list= )); )); )); Macro referenced in 4b. Die Auswertung funktioniert dann durch Fallunterscheidung, wobei die Länge der Operandenliste im match geprüft wird (siehe Tipp auf dem Blatt). "eval.ml" 4b ≡ open Arith_ast exception Arity;; h Die Operatorenliste 4a i let rec eval : pexp -> (pid * int) list -> int = fun e vars -> match e with Pexp_id(v) -> List.assoc v vars | Pexp_cint(i) -> i | Pexp_apply(op,[i;j]) -> let f=List.assoc op operators in f (eval i vars) (eval j vars) | Pexp_apply(_,_) -> raise Arity;; h Hauptprogramm 3b i