F-Sharp
Vorlage:Hinweisbaustein Vorlage:Hinweisbaustein
| F# | |
|---|---|
| colspan="2" class="notheme" style="text-align:center; background-color:#Vorlage:Standardfarbe;" | Datei:Fsharp logo.png | |
| Basisdaten | |
| Paradigmen: | multiparadigmatisch: funktional, imperativ, objektorientiert |
| Erscheinungsjahr: | 2002 |
| Designer: | Lua-Fehler in Modul:Wikidata, Zeile 1686: attempt to index field 'wikibase' (a nil value) |
| Entwickler: | F Sharp Software Foundation, Don Syme, Microsoft, |
| Aktuelle Version: | 7.0<ref>Announcing F# 7. 9. November 2021, abgerufen am 14. September 2023 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)).</ref> (8. November 2022) |
| Typisierung: | statisch, stark, implizit |
| Beeinflusst von: | Objective CAML, C#, Haskell, Elm |
| Beeinflusste: | Elm, F*, LiveScript, Elixir |
| Betriebssystem: | plattformübergreifend |
| Lizenz: | Apache-Lizenz 2.0 |
| F# Software Foundation | |
F# (gelesen: F {{Modul:Vorlage:lang}} Modul:Multilingual:153: attempt to index field 'data' (a nil value); englische Aussprache [<templatestyles src="IPA/styles.css" />]) ist eine typsichere Multi-Paradigmen-Sprache mit starkem Fokus auf funktionale Programmierung für das .Net-Framework. Die Syntax ähnelt der von OCaml sehr stark, da diese Sprache als Vorbild für die Implementierung der funktionalen und imperativen Sprachelemente diente. Im Gegensatz zu OCaml hat F# kein strukturiertes Typsystem, sondern ein normatives, um bessere Kompatibilität mit C# zu erreichen.
Die objektorientierte Seite von F# ist deshalb auch signifikant anders als die in OCaml.
F# ist voll interaktionsfähig mit allen anderen Sprachen des .NET-Systems und bietet durch das .Net-Framework und Mono die Möglichkeit, den Code sowohl auf Windows als auch auf Linux, der BSD- und illumos-Familie und macOS einzusetzen. Via Xamarin sind auch Android und iOS als Zielplattformen möglich.
Ursprünglich wurde F# als Forschungsprojekt von Microsoft Research entwickelt, derzeit wird es von Microsofts Entwicklungsabteilung und der F# Software Foundation fortgeführt. F# wurde als Teil von Visual Studio 2010 erstmals offiziell unterstützt und mit ausgeliefert.<ref>F# to ship as part of Visual Studio 2010. Don Syme’s WebLog on the F# Language and Related Topics</ref> Im November 2010 wurde F# sowie zugehörige Compiler und Bibliotheken unter der Apache-Lizenz 2.0 freigegeben.
Einige Sprachmerkmale
Werte
In überwiegend imperativen Sprachen sind Variablen das primäre Sprachkonstrukt, um Werte zu speichern. Dies geschieht in funktional orientierten Programmiersprachen wie F# durch unveränderliche (englisch: „immutable“) Sprachkonstrukte. Mit dem häufig eingesetzten Schlüsselwort let können Werte eines bestimmten Typs deklariert werden.
<syntaxhighlight lang="fsharp"> let pi = 3.14159265 let name = "John" </syntaxhighlight>
F# bietet Typableitung, d. h. Typen von Ausdrücken werden automatisch ermittelt. Beispielsweise bekommt pi automatisch den Typ des Gleitkommazahl-Literals zugewiesen.
Veränderliche Variablen sind mit dem mutable Schlüsselwort möglich und werden mit dem Zuweisungsoperator <- verändert. Dies wird in den meisten Fällen nur selten getan, weil die beschriebene Unveränderlichkeit von Werten als passender zur Sprachphilosophie gesehen wird. Dies nennt sich in F# auch functional first, also „funktional-zuerst“.<ref>Functional-first Programming with F#. Abgerufen am 14. September 2023 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)).</ref>
<syntaxhighlight lang="fsharp"> let mutable x = 10 x <- 15 </syntaxhighlight>
Werte im Nachhinein zu verändern, ist auch durch die Verwendung von sogenannten reference cells möglich:
<syntaxhighlight lang="fsharp"> let x = ref 0 // x hat den Typ "int ref", ist also eine Referenz auf einen Integer x := 5 // x wird ein neuer Wert zugewiesen printfn "%i" !x // Mittels des "!"-Operators wird x dereferenziert. Gibt 5 aus. </syntaxhighlight>
Funktionen
Funktionen werden wie andere Werte mit let deklariert und können Parameter erwarten:
<syntaxhighlight lang="fsharp">
let square x = x * x
let add x y = x + y
</syntaxhighlight>
Funktionen können Funktionen als Parameter erwarten (siehe Funktion höherer Ordnung): <syntaxhighlight lang="fsharp"> let do_twice f x = f (f x) </syntaxhighlight>
Die Typen der Parameter werden automatisch erkannt, können aber auch explizit deklariert werden: <syntaxhighlight lang="fsharp"> let add (x: int) (y: int) :int = x + y let do_twice (f : int -> int) (x: int) = f (f x) </syntaxhighlight>
Die Anweisung
<syntaxhighlight lang="fsharp">
printfn "%A" (do_twice square 5)
</syntaxhighlight>
gibt 625 (das Quadrat des Quadrats von 5) aus. Die Funktion do_twice kann mit Hilfe des Kompositionsoperators und nach Eta-Reduktion auch als
<syntaxhighlight lang="fsharp">
let do_twice f = f >> f
</syntaxhighlight>
geschrieben werden.
Im obigen Beispiel wird für square der Typ <syntaxhighlight lang="fsharp" style="white-space:nowrap" inline>int -> int</syntaxhighlight> ermittelt, das heißt, square ist eine Funktion, die einen Parameter vom Typ int erwartet und einen Wert vom Typ int zurückgibt. Für <syntaxhighlight lang="fsharp" inline>do_twice</syntaxhighlight> erhält man den Typ <syntaxhighlight lang="fsharp" style="white-space:nowrap" inline>('a -> 'a) -> 'a -> 'a</syntaxhighlight>. Dies bedeutet, do_twice ist eine Funktion, die als ersten Parameter einen Wert vom Typ <syntaxhighlight lang="fsharp" style="white-space:nowrap" inline>('a -> 'a)</syntaxhighlight> (eine Funktion mit einem Parameter vom Typ <syntaxhighlight lang="fsharp" inline>'a</syntaxhighlight> und einem Rückgabewert vom Typ <syntaxhighlight lang="fsharp" inline>'a</syntaxhighlight>) bekommt. Als zweiten Parameter erhält sie einen Wert vom Typ <syntaxhighlight lang="fsharp" inline>'a</syntaxhighlight> und sie gibt einen Wert vom Typ <syntaxhighlight lang="fsharp" inline>'a</syntaxhighlight> zurück. <syntaxhighlight lang="fsharp" inline>'a</syntaxhighlight> hat hier die Rolle einer Typvariable (grob vergleichbar mit Generic- oder Template-Parametern in Java/C++, siehe Polymorphie (Programmierung)).
In F# werden Parameter ohne Klammern etc., nur durch Leerzeichen getrennt, an die Funktion übergeben. Nur wenn als Parameter der Rückgabewert einer anderen Funktion benötigt wird, müssen Klammern gesetzt werden, um die Evaluierungsreihenfolge der Ausdrücke zu definieren. Bei <syntaxhighlight lang="fsharp" style="white-space:nowrap" inline>printfn "%A" (add 5 8)</syntaxhighlight> gehören die Werte 5 und 8 zur Funktion <syntaxhighlight lang="fsharp" inline>add</syntaxhighlight>; deren Rückgabewert ist ein Parameter für die Funktion <syntaxhighlight lang="fsharp" inline>printfn</syntaxhighlight>.
F# ermöglicht Closures und verwendet Currying automatisch:
<syntaxhighlight lang="fsharp"> let add x y = x + y let inc = add 1 </syntaxhighlight>
In der Definition von inc wird der erste Parameter der Funktion add an den Wert 1 gebunden. Das Ergebnis dieser partiellen Funktionsanwendung ist eine neue Funktion mit nur noch einem Parameter. Die Auswertung des Ausdrucks
<syntaxhighlight lang="fsharp">
inc 5
</syntaxhighlight>
liefert als Ergebnis 6.
F# unterstützt Tupel: <syntaxhighlight lang="fsharp"> let u = (3, 6) let v = (2, -3) let add (a, b) (c, d) = (a + c, b + d) let x, y = add u v </syntaxhighlight>
F# bietet Discriminated Unions<ref>Unterscheidungs-Unions, auf learn.microsoft.com</ref> und Pattern Matching:
<syntaxhighlight lang="fsharp"> // Ein Element vom Typ Baum ist entweder ein "Ast" und enthält zwei Elemente vom Typ "Baum", // oder es ist ein "Blatt" und enthält einen Integer type Baum = | Ast of Baum * Baum | Blatt of int
let rec baumSumme x =
match x with | Ast(l, r) -> baumSumme l + baumSumme r | Blatt(x) -> x
</syntaxhighlight>
Ebenso gibt es Type Provider für die typsichere Verarbeitung externer Daten mit IntelliSense.<ref>Type Provider</ref>
In F# ist auch objektorientiertes Programmieren möglich. Beispiel für eine Klassendeklaration:
<syntaxhighlight lang="fsharp"> type Person =
val name : string
val mutable age : int
new(n, a) = { name = n; age = a }
member x.Name = x.name
member x.Age
with get() = x.age
and set(v) = x.age <- v
member x.Print() = printfn "%s ist %i Jahre alt." x.name x.age
</syntaxhighlight>
Nullzeiger werden nur für die Interaktion mit Klassen aus dem .Net-Framework benötigt.
Syntax
Im F#-Code sind zwei Syntaxformen möglich: einfache Syntax und ausführliche Syntax. Die einfache Syntax wird standardmäßig verwendet.
Beispiel für die einfache und ausführliche Syntax:
| einfache Syntax | ausführliche Syntax |
|---|---|
|
<syntaxhighlight lang="fsharp"> let mutable x = 1 while x < 3 do x <- x + 1 </syntaxhighlight> |
<syntaxhighlight lang="fsharp"> let mutable x = 1 while x < 3 do x <- x + 1 done </syntaxhighlight> |
|
<syntaxhighlight lang="fsharp"> type Person = val name : string val mutable age : int </syntaxhighlight> |
<syntaxhighlight lang="fsharp"> type Person = class val name : string val mutable age : int end </syntaxhighlight> |
Bei der einfachen Syntax sind die Einrückungen zwingend erforderlich, bei der ausführlichen könnte man sie auch weglassen.
Entwicklungsumgebung und Compiler
F#-Code wird kompiliert, hierbei entsteht Zwischencode in der Common Intermediate Language (CIL), genau wie bei Programmen, die in C# oder VB.NET geschrieben wurden.
Es gibt auch eine interaktive Umgebung bzw. F#-Interpreter, F# Interactive oder kurz FSI. Damit kann man den Code direkt in der Konsole schreiben. Eingaben im Interpreter sind mit ;; abzuschließen, wodurch auch mehrzeilige Eingaben ermöglicht werden. Nach dem Kompilieren führt F# Interactive den Code aus und schreibt die Signatur aller kompilierten Typen und Werte in das Konsolenfenster. Auch Fehlermeldungen werden so ausgegeben.<ref>Microsoft F# Interactive-Referenz</ref>
Dieser Interpreter erlaubt in unterstützten Editoren wie Visual Studio Code die Ausführung von Code ohne vorherige Kompilierung, so wie dies von dynamischen Sprachen bekannt ist.
Außerdem gibt es den Fable<ref>Fable · JavaScript you can be proud of! Abgerufen am 14. September 2023.</ref>-Übersetzer, mit dessen Hilfe sich F#-Code in JavaScript, Rust, Python, PHP und Dart übersetzen lässt.
Beispiele
Folgende Beispiele eines Hallo-Welt-Programms geben „Hello World“ aus.
<syntaxhighlight lang="fsharp"> let main = System.Console.WriteLine("Hello World") </syntaxhighlight>
oder
<syntaxhighlight lang="fsharp"> printfn "Hello World" </syntaxhighlight>
Die folgende Funktion implementiert die rekursive Ackermannfunktion: <syntaxhighlight lang="fsharp"> let rec ack m n =
if m = 0 then n + 1 else if n = 0 then ack (m - 1) 1 else ack (m - 1) (ack m (n - 1))
</syntaxhighlight>
Literatur
- Oliver Sturm: F# Einstieg und praktische Anwendung. entwickler.press, 2012, ISBN 978-3-86802-083-0.
Weblinks
- The F# Software Foundation. Abgerufen am 5. Juni 2014 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)).
- F# Dokumentation. In: Microsoft Docs. Microsoft, abgerufen am 27. April 2014.
- F# compiler, Basisbibliothek und Tools auf GitHub. Abgerufen am 9. Juni 2020 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)).
- F# at Microsoft Research. Microsoft Research, abgerufen am 27. April 2014 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value), F#-Homepage von Microsoft Research).
- The F# Survival Guide. CTO Corner, archiviert vom Vorlage:IconExternal am 15. Juli 2011; abgerufen am 27. April 2014 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)).
- F# Cheatsheet. In: Github. Abgerufen am 9. Juni 2020 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)).
- Scott Wlaschin: Twenty six low-risk ways to use F# at work. In: F# for fun and profit. 20. April 2014, abgerufen am 9. Juni 2020 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)).
- Try F#. F# Software Foundation, abgerufen am 9. Juni 2020 (Lua-Fehler in Modul:Multilingual, Zeile 153: attempt to index field 'data' (a nil value)). Interaktives Tutorial.
Belege
<references />