OCaml und F# Silvio Feig, Martin Benedict Was ist OCaml? ● 1996 entwickelt ● funktionale Programmiersprache ● ● mit objektorientierten und imperativen Elementen kompilierte und interpretierte Sprache Hello World in Ocaml print_endline „hello, world“ Entwicklungshistorie OCaml Compiler und Interpreter Was ist F#? ● aus OCaml hervorgegangen ● OCaml-Syntax ● Zugriff auf .net-Framework möglich ● Entwickler Microsoft Hello World in F# printfn „hello, world“ F# Compiler und Interpreter Unterschiede OCaml und F# • OCaml besitzt ein mathematisch orientiertes Modulsystem, F# ein objektorientiertes • F# besitzt keine Funktoren – Realisierung über Interfaces • F# lässt keine doppelten Definitionen zu • F# weniger striktes Typsystem – null-Wert vorhanden – Überladung möglich – dynamische Typprüfung und Umwandlung Datentypen in OCaml ● ● unit-type ● für Funktionen mit Seiteneffekten (Beispiel später) ● wie () in Haskell ● wie void in C primitive Datentypen Datentyp float Beispiel 2.4 int 3 bool true char 'x' string "abc" Unterschiede zu Datentypen in F# ● Weiter in OCaml nicht vorhandene Datentypen ● ● ● Byte, Int, Long, Single, Native Int, Decimal, Big Number unsigned Byte, unsigned Int Umwandlung mit Typnamen let myFloat = float 2 let myInt = int 2.4 Variablendefinition ● ● ● Variablendefinition erfolgt mit let definierte Variablen können keinen neuen Wert erhalten, sie sind immutable Definitionen können verschachtelt werden: let z = let x = 2 in let y = 3 in x + y;; → Codebeispiel Operatoren ● übliche algebraische Operatoren +,-,*,/,%,** ● bitweise Operatoren und logische Operatoren ● In OCaml für float separate Operatoren z.B. /. ● In F# Operatoren für alle numerischen Datentypen nutzbar, aber nur für gleiche Typen Funktionsdefinition ● Funktionsdefintion erfolgt mit let let square x = x*x ● Lambda-Ausdrücke mit fun let subhalf = fun x -> x-(x/2.0) ● rekursive Funktion mit rec let rec abc x = … abc ● Funktionen sind Datentypen z.B. val square : float -> float Funktionen ● Es existiert immer ein Rückgabetyp (unit ist auch ein Typ) ● Typinferenz erfolgt automatisch ● kann beeinflusst werden durch casting let myFunc (a:float) = … ● Funktionen können geschachtelt werden ● ● Rückgabe steht immer am Ende des Schachtelungsblocks Funktionsausführung erfolgt stets bei Definition → Beispiel → Codebeispiel Ausgabe und Eingabe F# OCaml Ausgabe printfn "hello, " ● output_string stdout "world\n" die Ausgabefunktionen sind prinzipiell vom Typ string->unit Eingabe System.Console.ReadLine() ● ● Nutzt das .net zum Einlesen Funktion vom Typ: unit->string input_line stdin;; ● ● Liest von Input-Stream Funktion vom Typ: in_channel->string → Codebeispiel Imperative Elemente und Alternativen ● Variablen können mit Schlüsselwort versehen werden und sind dann änderbar. F# Schlüsselwort: mutable ● Zuweisung: <- OCaml Schlüsselwort: ref ● Zuweisung: := ● Derefernzierung: ! ● ● let mutable x = 2 x <- 3 let x = ref 3;; x := !x + 1;; Imperative Elemente und Alternativen ● Konstruktion von for und while-Schleifen sind möglich while (F#) while n <= 10 do let sq = n * n printfn "%d %d" n sq n <- n + 1 ● ● for (OCaml) for n = 1 to 10 do printf "%d %d" n (n * n) done;; Alternativen sind mit if/then/else/elif möglich Bei Alternativen müssen die Typen nach then und else übereinstimmen → Codebeispiel Tupel ● Definition in runden Klammern let myTuple = (2,3,“abc“) ● Klammern können auch wegfallen ● Zugriff mit fst,snd auf Tupel der Größe 2 ● Verschiedene Datentypen in Tupeln möglich Records ● ● ● mit struct vergleichbar vorher mit type festlegen let banane = { name = „Banane“; farbe = „yellow“; vitamine = [„a“;“b“] } → Codebeispiel Listen ● Definition von Listen mit ● ● ● :: - Verkettungsoperator (cons) [a;b] - In geschweiften Klammern mit Semikolon getrennt @ - Verkettung von Listen (concat) ● Immer der gleiche Datentyp ● am Ende immer leere Liste a::b::[] ● Liste ist unveränderbar Arrays ● ● ● Array sind Felder auf die indiziert zugegriffen werden kann arr.[2] Inhalte des Arrays können modifiziert werden arr.[2]<-“Kirsche“ Definition von Arrays let myArray = [|2;4;6;8|] Sequenzen werden in geschweiften Klammen definiert let range = seq { 0 .. 2 .. 6} ● ● ● werden im Gegensatz zu Listen lazily berechnet Umwandlung von List und Arrays in Sequenzen und umgekehrt ist möglich und wird z.T. Auch implizit durchgeführt toList, ofList, toArray, ofArray Rekursionsschemata ● ● bekannte Rekursionsschemata map, fold, zip jeweils für Arrays, Sequenzen und Listen List.map (fun x -> x*x) list Array.fold (+) 0 array Seq.zip seq1 seq2 → Codebeispiel Types ● ● ● ● Typen werden mit type definiert objektorientiert mit member-Schlüsselwort, Zugriff mit obj.<variable> Definition von Methoden mit obj.<methName>(<params>) z.B. ein Binärbaum (im Beispiel) Pattern Matching ● Pattern Matching erfolgt mit match ● Matching muss erschöpfend sein ● auch komplexe Typen sind möglich let firstElement elems = match elems with | h :: t -> h | [] -> „none“ Pattern Matching Quelle: Syme, Don: Expert F# → Codebeispiel Lazy Evaluation ● ● ● Verwendung mit Schlüsselwort lazy Berechnung wird erst ausgeführt, wenn Lazy.force <variable> aufgerufen wird Unterschied zu Haskell, man muss selbst mit force entscheiden, wann berechnet wird Monaden ● ● existieren in F# (Computation Expression) und OCaml z.B. in F# Maybe-Monade mit Option.None/Option.Some, MaybeBuilder auch mit Syntactic Sugar maybe{ let x = 12 let! y= Some 11//maybe.Bind(Some 11, f) return x+y } Pipeline-Operator (F#) ● |> ist der Pipeline-Operator gibt Ergebnis der letzten Berechnung an die nächste Funktion let (|>) x f = f(x) ● getwebsite |> findtitle |> countcharacters → Codebeispiel Currying und Closures ● Currying ist auch in OCaml und F# möglich ● Zerlegung von Funktionen in Funktionen mit 1 Parameter let f x y = x * y let fwithtwo = f 2 let result = fwithtwo 4 Currying und Closures man kann sich Funktionen „bauen“ lassen let giveFunction a = ● let createdFunction (x:int) = (x+a)*(x+a) createdFunction let func4 = giveFunction 4 let erg = func4 2 → Codebeispiel Exceptions ● es können Exceptions auftreten ● Werfen von Exceptions mit raise ● Fangen von Exceptions mit try with try raise(Failure “A problem”) with | Failure s - > s;; → Codebeispiel Nutzen des .net-Frameworks (F#) ● ● Funktionen von Klassen sind nutzbar In F# haben Funktionen und Funktionen höherer Ordnung eine Entsprechung in der .net-Bibliothek z.B. List.map entspricht Microsoft.FSharp.Collections.List.map ● Zugriff auf Window, XDocument usw. ist erlaubt → Codebeispiel Fazit ● ● OCaml und F# sind sehr mächtige Sprachen F# scheint für produktiven Einsatz recht gut geeignet zu sein ● Zugriff auf Systemschichten über .net ● Verwendung von C# und VBA-Bibliotheken ● XML-Verarbeitungsmöglichkeiten des .netFrameworks Ende der Präsentation für Fragen stehen wir zur Verfügung Quellen ● Syme, Don; Granicz, Cisterno, Antonio: Expert F#, 2007 ● Harrop, J. D.: OCaml for Scientists, 2005 ● Smith, Chris: Programming F#, 2010 ● Jason Hickey: Introduction to Objective Caml, 2008, www.cs.caltech.edu/courses/cs134/cs134b/book.pdf ● Xavier Leroy: The Objective Caml system: Documentation and user’s manual 3.12, 2008, http://caml.inria.fr/pub/docs/manualocaml/index.html ● MSDN F# Referenz, http://msdn.microsoft.com/en-us/library/dd233181.aspx ● http://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions ● http://lookingsharp.wordpress.com/2010/02/27/fibonacci-fun-with-fsharp/ ● http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/ ● http://blog.matthewdoig.com/?p=98 ● http://www.heise.de/developer/artikel/F-funktionales-Pendant-zu-C-1140553.html ● http://www.codingforfood.com/2010/09/f-infinite-sequences.html ● http://enfranchisedmind.com/blog/posts/a-monad-tutorial-for-ocaml/ ● Caml Website, http://caml.inria.fr/