F Sharp
| Paradigma: | multiparadigmatický |
|---|---|
| Vznikl v: | 2002 |
| Autor: | Microsoft Research (Don Syme) |
| Poslední verze: | 2.0 / 12.4 2010 |
| Typová kontrola: | statické, silné, implicitní |
| Ovlivněn jazyky: | OCaml, C#, Haskell, ML, LINQ |
| Ovlivnil jazyky: | - |
| OS: | Multiplatformní (.NET Framework, Mono) |
| Licence: | Microsoft Research Shared Source license agreement ("MSR-SSLA") |
| Web: | Microsoft Research - F# |
F# (vyslovované anglicky jako F Sharp, /ef ʃɑɹp/, doslova to označuje notu fis) je multiparadigmatický programovací jazyk pro .NET spojující funkcionální přístup s imperativním objektově orientovaným přístupem. Syntaxe jazyka vychází z ML a OCaml a dále je ovlivněna jazyky Haskell, C# a LINQ. F# je plně podporovaným jazykem pro platformu .NET a je součástí Visual Studia 2010[1]. V současné době se o vývoj jazyka stará Microsoft Research.
Obsah |
Cíle jazyka a souhrn vlastností[editovat]
F# byl vyvinutý jako varianta ML s mnoha konstrukcemi převzatými z OCaml. Na rozdíl od mnoha skriptovacích jazyků se rychlostí blíží k C# (především díky silné typovosti). Podporuje také řadu dynamických programovacích technik jako je například reflexe. F# umožňuje propojení s dalšími jazyky včetně snadné implementace DSL, bezproblémově spolupracuje se všemi jazyky .NET.
Microsoft Research[2] zmiňuje mezi hlavní výhody jazyka tyto:
- funkcionální jazyk se stručnou syntaxí a implicitním typováním
- možnost interaktivního skriptování (jako v Pythonu)
- kombinace typové bezpečnosti a implicitního typování (jako v ML)
- výkon na úrovni C#, nativní běh na .NET frameworku
- přístup ke všem knihovnám .NET
- integrovanost a plná podpora ve Visual Studiu
F# je silně typový jazyk který ovšem používá implicitní typování (datový typ proměnné se nemusí specifikovat explicitně, překladač ho rozpozná podle přiřazované hodnoty). Jako jazyk pro .NET podporuje F# všechny typy z .NET frameworku ale navíc přidává několik neměnných typů (změna jejich hodnoty je možná pouze vytvořením nové kopie) svázaných se specifickými vlastnostmi jazyka a používaných především pro úlohy funkcionálního programování. Těmito typy jsou: tuple, record, discriminated union, list a function. V této souvislosti stojí za zmínku, že i typy .NET jsou standardně v F# neměnné, opaku lze docílit použitím klíčového slova mutable.
Důležitou vlastností jazyka je interaktivní skriptování, které umožňuje komponenta F# Interactive[3]. Syntaxe jazyka se pro skriptování v některých detailech liší, navíc je možné používat tzv. light syntaxi. Jde ale jen o drobné rozdíly v ukončování příkazů.
Syntaxe jazyka[editovat]
Syntaxe jazyka jak už bylo řečeno vychází hlavně z ML a OCaml. Nejvýrazněji se na vzhledu kódu podepisují jazykové konstrukce implicitního typování a pattern matchingu.
V jazyce existují komentáře dvojího typu, řádkové uvozené // a víceřádkové začínající znaky (* a končící *).
Proměnná (name v terminologii F#, protože se nejedná o proměnné v klasickém slova smyslu, mohou totiž uchovávat i funkce) se deklaruje tak že jejímu názvu předchází klíčové slovo let, které zároveň znamená automatické určení typu proměnné (podobně jako var v C# 3.0).
Hodnota se proměnné přiřadí při deklaraci pomocí operátoru =, pokud je potřeba ji později změnit (pouze v kontextu měnitelných proměnných označených klíčovým slovem mutable), slouží k tomu operátor <-.
Pro spolupráci s .NET je důležitá konstrukce pro tvorbu objektů převzatá z C# - objekty se tvoří pomocí klíčového slova new. Pro „oznámení“ používání nějakého namespace se používá klíčové slovo open (ekvivalent using v C#). K vlastnostem a metodám se přistupuje klasicky přes tečkovou notaci a metody se volají s parametry v závorkách.
Mezi literály, mimo klasické čísla a řetězce, patří také některé konstrukce F#, jako tuple (viz dále).
Datový typ (třída) se deklaruje pomocí klíčového slova type a to jak typy .NET tak i speciální typy F#, konkrétněji viz níže nebo v [3].
Funkce se definují několika způsoby, buď pomocí klíčového slova fun, nebo jako výraz kde na levé straně jsou vedle let a názvu také parametry a za rovnítkem následuje definice. Rekurzivní funkce musejí být jako rekurzivní explicitně definovány pomocí klíčového slova rec.
Důležitou konstrukcí F# je pattern matching, umožňuje porovnávat výraz s jinými a podle toho rozhodnout o dalším postupu výpočtu, přitom pojmenuje a tím získá přístup na složky dat. Nejčastější aplikací je rozložení typu tuple (viz níže) nebo řízení toku programu konstrukcí match proměnná with | když-výraz -> tak-výraz kde část po | se může libovolněkrát opakovat. Tato konstrukce může nahradit řadu ifů a switchů a zlepšit čitelnost kódu.
F# podporuje i základní cykly. Ty jsou vlastně funkce bez návratové hodnoty (v terminologii jazyka F# „výrazy typu unit“).
Klasický cyklus for je uvozen klíčovým slovem for, následuje řídící proměnná, rovnítko, počáteční hodnota, klíčové slovo to nebo downto (určující přičítání/odčítání jedničky), koncová hodnota, do a tělo cyklu. Jinak řečeno: for řídící_prom = počáteční_hodnota [down]to konečná_hodnota do tělo_cyklu.
Cyklus známý jako foreach (projde celé pole a do každé iterace nabídne jednu položku) se zapíše [for jedna_položka in procházené_pole do tělo_cyklu ].
Cyklus while má jednoduchou syntaxi while podminka do tělo_cyklu.
Datové typy F#[editovat]
Všechny typy F# jsou aliasy pro speciální generické datové typy .NET. Mimoto jsou v F# další aliasy na často používané třídy .NET, například obj pro System.Object nebo ResizeArray<T> pro System.Collections.Generic.List<T> (kvůli odlišení od F# typu List)[3].
Tuple[editovat]
Tuple je nejjednodušší speciální datový typ v F#. Umožňuje „zabalit“ dvě nebo více nepojmenovaných hodnot každou libovolného typu. Množství i typ hodnot musejí být známy už při překladu. Je to v podstatě primitivní přepravka vhodná pro interní použití jež ani nemusí být explicitně definována jako typ (vytvoří se automaticky při použití). Každý tuple je odvozen od generické třídy Tuple<_,_>.
Příklad uložení jména se soundexovým kódem a jeho rozložení na hodnoty pomocí jednoduché konstrukce pattern matching:
let mrCarroll = ("Carroll", "C64") let (name, soundex) = mrCarroll
Tentýž příklad v interaktivním režimu (s odpověďmi konzole):
> let mrCarroll = ("Carroll", "C64");; val mrCarroll : string * string = ("Carroll", "C64") > let (name, soundex) = mrCarroll;; val soundex : string = "C64" val name : string = "Carroll"
Record[editovat]
Record (záznam) je rozšířeným typem tuple. Umožňuje pojmenovat jednotlivé datové složky a přistupovat k nim známou „tečkovou notací“, velmi se tak podobá typu struct v C#. Record už musí být definován jako typ. S .NET je record provázán tak že při jeho definici se vytvoří třída a jednotlivé datové složky má jako atributy.
Příklad vytvoření Recordu a odvození z něj druhého:
type ShopItem = { Name:string; Price:int } let commonCar = { Name="car"; Price=1000 } let luxuryCar = { commonCar with Price=5000 }
Discriminated union[editovat]
Discriminated union je typ který umožňuje uložení hodnoty jednoho z různých nabídnutých typů. O konkrétním typu se rozhoduje podle volaného konstruktoru.
Příklad elegantní reprezentace binárního stromu pomocí Discriminated union. Zápis int * BinaryTree * BinaryTree vyjadřuje typ tuple s třemi položkami, první typu int a zbylé dvě typu BinaryTree.
type BinaryTree = | Fork of int * BinaryTree * BinaryTree | Leaf of int let heap = Fork (2,Fork (17,Fork (22,Leaf (49),Leaf (31)),Leaf (51)),Fork (29,Leaf(11),Leaf (25)))
List[editovat]
List (seznam) je typický spojový seznam tvořený vždy položkou a odkazem na zbytek seznamu v zápise první_položka::zbytek_seznamu (tzv tail operátor známý např. z LISPu) nebo ve zkráceném zápise [ hodnota1;hodnota2;... ]. Prázdný seznam se zapíše [].
F# obsahuje také speciální jazykovou konstrukci pro tvorbu typu array který ale je standardním typem .NET a není tedy neměnný. Lze ho vytvořit konstrukcí [| hodnota1;hodnota2;... |].
Příklad dvou možných zápisů tvorby seznamu List:
let list1 = 1::2::3::[] let list2 = [1; 2; 3]
Function[editovat]
V F# je každá funkce typem. Funkce jsou také neměnným typem, ale F# nabízí řadu možností jak upravovat jejich volání, například použitím curryingu nebo skládáním funkcí, funkce mohou být předávány jako parametry dalších funkcí, F# také podporuje lambda funkce.
Příklad definice jednoduché funkce pro sčítání a následně z ní odvozené funkce pro přičtení 10tky (jednoduchá ukázka techniky zvané currying) a nakonec volání které vyústí v hodnotu 20 uloženou v proměnné twenty:
let add = ( fun lhs rhs -> lhs + rhs ) let add10 = add 10 let twenty = add10 10
Funkci add lze také nadefinovat takto:
let add lhs rhs = lhs + rhs
Příklad funkce sumy všech hodnot v Listu. Řešeno pro funkcionální jazyky typickým způsobem (odpojení první položky, její zpracování, a rekurzivní volání na zbytek pole), využívá pattern matching a ilustruje deklaraci rekurzivní funkce klíčovým slovem rec.
let list = [ 1 .. 10 ] (* seznam se všemi položkami od 1 do 10 *) //pomocná funkce s akumulační proměnnou acc let rec sumAcc acc list = match list with | top::tail -> sumAcc (acc + top) tail | _ -> acc //výsledná funkce sumy let sum list = sumAcc 0 list let res = sum list (* val res : int = 55 *)
K předchozímu příkladu stojí za zmínku i vlastnost jazyka F# podobná se zásobníkovými jazyky, totiž že obě funkce by se mohly jmenovat stejně a program by fungoval správně, druhá by skryla první a sama by ji uvnitř bez problémů volala. Je to dáno způsobem, jakým v F# funguje obor hodnot proměnné[3].
Vlastnosti jazyka[editovat]
F# používá pattern matching jednak aby převedl jména na hodnoty, ale také pro kontrolu, zda mají data požadovanou strukturu nebo hodnotu. Pattern matching může být použit se všemi standardními F# typy, nejčastěji s typy tuple a discriminated union. Jazyk F# také podporuje obecnější pattern matching pomocí tzv. active patterns, které umožňují kontrolu dat z různých pohledů na typ.
Protože je jazyk F# určen pro platformu .NET (musí vyhovovat požadavkům CLI) a protože jako jedno z paradigmat podporuje imperativní objektově orientované programování, obsahuje konstrukce pro tvorbu smyček for a while a .NET tříd i rozhraní (v terminologii F# společně nazývané object types – objektové typy) v podobném rozsahu jako ostatní jazyky .NET[3].
F# od verze 1.9.1 obsahuje tzv. sequence expressions (sekvenční výrazy)[4] zapisované jako seq{ ... } , které obsahují sekvenční bloky různých konstrukcí. Na rozdíl od ostatních jazykových konstrukcí F# jsou „líně vykonávané“ (lazily evaluated, tj. vyhodnocují se až v momentě využití). Mohou být použity pro filtrování i pro zkrácení zápisu (mnoharozměrné) kolekce. Jsou základem pro podporu LINQ a důležité pro asynchronní volání ( async{ ... } ).
F# je díky kombinaci vlastností funkcionálních a objektových jazyků vhodný na programování asynchronních operací a vícevláknových aplikací pro víceprocesorové systémy.
Jako jedno z paradigmat které F# do jisté míry přejímá je Language-oriented programming[3], usnadňuje tak tvorbu DSL, ovšem omezenou syntaxí jazyka (lze „pouze“ změnit význam příkazů F#). Nejjednodušší příklad je využití discriminated unions jako deklarativní jazyk na vyhodnocování aritmetických výrazů[3]. F# rozšiřuje schopnosti .NET System.Reflection a umožňuje tak meta-programming (meta programování – manipulování s kódem jako s daty).
Název jazyka[editovat]
Název jazyka F# je, podobně jako v ostatních jazycích .NET (počínaje jazykem C#), odvozen z hudební notace, kde křížek označuje zvýšení noty o půl tónu a v tomto případě by označoval notu fis, tedy F zvýšené o půl tónu.
Křížek na počítačové klávesnici (#) a křížek v hudební nauce (♯) jsou dva odlišné znaky. Pro zápis názvu jazyka F Sharp se nepoužívá znak hudebního křížku z technických důvodů, protože tento se na standardní klávesnici nevyskytuje. Pro zjednodušení se tak používá klasický křížek.
Příklady[editovat]
Příklad nejjednodušší aplikace:
printfn "Ahoj světe."
Příklad demonstrující syntaxi jazyka na funkci rekurzivně počítající faktoriál:
let rec factorial n = match n with | 0 -> 1 | _ -> n * factorial (n – 1)
Příklad cyklu for, vypíše čísla od 1 do 10:
for n = 1 to 10 do printfn "%d" n
Příklad cyklu while:
let mutable n = 3 while n < 10 do n <- (n+1) printfn "%d" n
Příklad cyklu for (foreach) v F#, vrátí pole sudých čísel od 2 do 20:
let nums = [1..10] [ for num in nums do yield num*2 ]
Příklad jednoduché okenní aplikace .NET:
(* otevření formulářové knihovny .NET *) open System.Windows.Forms (* vytvoření okna(Form) a nastavení vlastností *) let form = new Form(Visible=true, TopMost=true, Text="Welcome to F#") (* vytvoření nápisu(Label) s textem *) let label = let temp = new Label() let x = 3 + (4 * 5) (* nastavení hodnoty vlastnosti Text *) temp.Text <- sprintf "x = %d" x (* vrácení hodnoty (do proměnné label) *) temp (* přidání nápisu do okna *) do form.Controls.Add(label) (* spuštění aplikace *) [<STAThread>] do Application.Run(form)
Zdroje[editovat]
- ↑ SOMASEGAR, Sam. F# - A Functional Programming Language [online]. [cit. 2009-12-02]. Dostupné online.
- ↑ Microsoft Research [online]. [cit. 2009-12-02]. Dostupné online.
- ↑ a b c d e f g PETŘÍČEK, Tomáš. F# Language Overview [online]. [cit. 2009-12-01]. Dostupné online.
- ↑ SYME, Don. Some Details on F# Computation Expressions [online]. [cit. 2009-12-03]. Dostupné online.