F Sharp
- A szócikk címe technikai okok miatt pontatlan. A helyes cím: F#.
F# | |
Paradigma | funkcionális, imperatív, objektumorientált, többelvű |
Jellemző kiterjesztés | .fs, .fsi, .fsx, .fsscript |
Megjelent | 2005 (1.0 verzió) |
Tervező | Microsoft, Don Syme |
Fejlesztő | Microsoft, The F# Software Foundation |
Utolsó kiadás | 4.0 (2015. július 20.) |
Típusosság | statikus, erősen típusos, típus biztos |
Megvalósítások | .NET Framework, Mono |
Hatással volt rá | ML, OCaml, C#, Python, Haskell, Scala, Erlang |
Befolyásolt nyelvek | C# |
Operációs rendszer | platformfüggetlen |
Licenc | Apache Licenc |
Weboldal |
Az F# egy a .NET keretrendszerhez kapcsolódóan kifejlesztett, több programozási irányelv szerint is alkalmazható (többelvű), szigorúan típusos programozási nyelv. Alapjául az ML és OCaml nyelv szolgált, valamint kialakítására hatással volt még a C#, Python, Haskell, Scala valamint Erlang nyelv is. Elsősorban funkcionális programozási nyelvnek szánták, de alkalmazható az imperatív és objektumorientált elveknek megfelelően is.
Történet
[szerkesztés]Fejlesztése
[szerkesztés]A munkálatokat a kezdetektől Don Syme a Microsoft kutatási részlegének (Microsoft Research) munkatársa igazgatja, 2013-tól együttműködésben az F# Software Foundationnel. A nyelv alapjai és korai verziói még zárt fejlesztési folyamatban készültek a Microsoft és annak Cambridge-i kutatási részlege közreműködésével. A számos fejlesztő mellett kiemelt szerepe van a projektben Andrew Kennedynek, aki nagyban hozzájárult a .NET keretrendszer alapjaival való összehangolásban és a mértékegységek implementálásával.[1] Ennek a folyamatnak a során készült el a nyelv Microsoft Visual Studio integrációja is.
Napjainkban a nyelv további fejlesztése már nyílt módon folyik. A nyílt forrású fordító az F# Software Foundation gondozásában készült el.
Verziók
[szerkesztés]Verziószám | Megjelenés | Főbb fejlesztések |
---|---|---|
1.0 | 2005. május[2] |
|
2.0 | 2010. április[3] |
|
3.0 | 2012. augusztus[4] |
|
3.1 | 2013. október[5] |
|
4.0 | 2015. július[6] |
|
Áttekintés
[szerkesztés]Funkcionális programozás
[szerkesztés]Az F# szigorúan típusos nyelv, jellemzően pedig típuskikövetkeztetés segítségével dolgozhatunk. Így a programozónak nem kell a típusokat a kódban előre megadnia, azok futás időben kerülnek meghatározásra. Ugyanakkor a nyelv lehetőséget biztosít a típus explicit megadására is, amely indokolt lehet néhány ritka esetben.
A nyelvben azonosítók segítségével adunk nevet a kifejezéseknek, amik kiértékelésük alapján kapják meg az értéküket. Fontos megjegyezni, habár ez hasonlít az imperatív nyelveknél megszokott értékadáshoz, valójában okkal nevezzük ezeket azonosítónak és nem változónak, ugyanis a kiértékelést követően az azonosító értéke többé már nem változtatható meg (kivételt képez ez alól néhány későbbi láthatósághoz kapcsolódó eset, valamint imperatív programozási paradigma alkalmazása esetén vannak lehetőségek felüldefiniálásra). Ugyanakkor lehetőség van kifejezésként megadni az F#-ban elérhető függvényeket és programozási struktúrákat is, beleértve az if
, valamint a try
szerkezeteket és egyéb ciklus szervezéseket. Az ilyen azonosítókat a let
kulcsszó segítségével definiálhatjuk.
Egy egyszerű példa a let
használatára:
let x = 4 + 2 // az x azonosító ''immutable'' (azaz nem változtatható meg)
A kiértékelés után az x
nevű azonosító értéke 6
lesz.
Egy másik példa, ezúttal függvény definiálására:
let osszead x y = x + y
let eredmeny = osszead 4 6
A kiértékelés után az eredmeny
nevű azonosító értéke 10
lesz.
Az utóbbi példában jól látható, hogy F#-ban miként lehet a matematikában használatos függvény megadáshoz hasonlóan definiálni.
Matematikai megadás | Definiálás F#-ban |
---|---|
let f x = x * x
|
F#-ban a visszatérési érték nélküli funkciók és kifejezések unit
típusúak, amely a C# és C++ nyelvek void típusára emlékeztethet.
Az F# a következő elemi típusokat támogatja: byte, sbyte, int16, uint16, int32, uint32, int64, uint64, obj, float32, float64
Új típusokat a type
kulcsszóval határozhatunk meg. A funkcionális programozáshoz a nyelv a rendezett n-es (tuple), rekord, diszkriminánsos unió, lista és option típusokkal szolgál.
A rendezett n-es (tuple) egy olyan egyszerű adattípus, amellyel n darab értéket csoportosíthatunk, ahol n ≥ 0 és értékek akár különböző típusúak is lehetnek. A tuple elemeinek száma viszont mindig előre meghatározott lesz a definiálásakor és a futtatás végéig változatlan is marad, ezért az előre nem definiálható elemszámú adathalmazok tárolására nem alkalmas. Helyette a lista vagy tömb típus lehet a megfelelő választás. Jól hasznosítható, amennyiben egy egyszerűbb függvénynek több visszatérési értéke van. Ilyenkor az adott függvény visszatéréseként használva szükségtelenné teszi új osztályok deklarálását. Bonyolultabb struktúrájú visszatérési értékekkel rendelkező függvényeknél viszont célszerűbb a rekord típust használni.
Példa egy tuple megadására:
let tuple = (42, "Hello world!")
Ezen a rendezett n-es szerkezeten belül az első érték int ,míg a második string típusúnak lesz értelmezve.
A rekord valójában egy olyan rendezett n-esnek tekinthető szerkezet, amely névvel ellátott elemekkel rendelkezik: { Nev:string; Kor:int }
. Valamint abban is különböznek, hogy a rekordot előre deklarálni kell a type
konstrukcióval:
type Termek = { Nev:string; Ertek:int } // a rekord típus deklarációja
let t = { Nev="Teszt"; Ertek=42; } // meghatározzuk a 'Termek' értékét
A with
kulcsszóval másolatot készíthetünk egy rekordról. Mivel a rekord immutable tulajdonságú, azaz a tagjai nem módosíthatóak, ezért gyakran kell másolatot készítenünk róla, amiben egy vagy több elemén változtatást hajtunk végre:
let t2 = { t with Nev="Teszt2" } // a fenti példa után készítünk egy másolatot egy más 'Nev' értékkel
A diszkriminánsos unió típust olyan adattípusok reprezentálása használhatjuk, melyben a tárolt adatok opcionálisak. Hasonló, mint a C++ nyelvben használt unió típus, vagy a Visual Basic variant típusa. Itt viszont a deklarálásnál meg kell határoznunk úgynevezett eseteket, amelyeken belül minden típust is definiálnunk kell.
Egy egyszerű példa amelyben egy alakzatot deklarálunk ezzel a szerkezettel:
type Shape =
| Circle of float // a kör sugara
| EquilateralTriangle of double // a szabályos háromszög oldalhossza
| Square of double // a négyzet oldalhossza
| Rectangle of double * double // a téglalap a és b oldalának hosszai
Amint az látható, itt 4 esetről beszélhetünk: kör (Circle), szabályos háromszög (EquilateralTriangle), négyzet (Square) és téglalap (Rectangle). (A 3.1-es verziótól már nevet is adhatunk az egyes eseteken belül a mezőknek, viszont ez nem kötelező.)
Ha ki akarjuk számítani a fent definiált alakzatok területét, akkor a mintaillesztés módszeréhez (match
) kell fordulnunk:
let pi = 3.141592654
let area myShape =
match myShape with
| Circle radius -> pi * radius * radius
| EquilateralTriangle s -> (sqrt 3.0) / 4.0 * s * s
| Square s -> s * s
| Rectangle (h, w) -> h * w
let radius = 15.0
let myCircle = Circle(radius)
printfn "Kör területe, amelynek sugara %f: %f" radius (area myCircle)
let squareSide = 10.0
let mySquare = Square(squareSide)
printfn "Négyzet területe, amelynek oldalhossza %f: %f" squareSide (area mySquare)
let height, width = 5.0, 10.0
let myRectangle = Rectangle(height, width)
printfn "Téglalap területe amelynek egyik oldala %f, másik oldala pedig %f: %f" height width (area myRectangle)
A fenti kód futtatása a következő eredményt hozza:
Kör területe, amelynek sugara 15.000000: 706.858347
Négyzet területe, amelynek oldalhossza 10.000000: 100.000000
Téglalap területe amelynek egyik oldala 5.000000, másik oldala pedig 10.000000: 50.000000
Imperatív programozás
[szerkesztés]Az F# nyelv támogatja az imperatív programozási paradigmát is.
A használható szerkezetek a teljesség igénye nélkül:
for
cikluswhile
ciklus- tömbök deklarálása
[…, …]
- asszociatív tömbök, ún. szótárak deklarálása
dict […]
vagySystem.Collections.Generic.Dictionary<_,_>
Az azonosítók és mezők / elemek megjelölhetők mutable
tulajdonsággal, aminek hatására ezeknek az értéke később felülírható:
let mutable x = 1 // definiáljuk az 'x' azonosítót kezdeti '1' értékkel
x <- 3 // felülírjuk az 'x' értékét '3'-al
Hasonló megoldás, amennyiben például egy rekord típus adott elemét szeretnénk felülírni:
type Termek = {
Megnevezes: string
mutable Darabszam: int
}
let egyTermek = { Megnevezes = "Fapapucs"; Darabszam = 100 }
egyTermek.Darabszam <- egyTermek.Darabszam - 1
Ezen felül az F# elérhetővé teszi az összes CLI típust és objektumot, amelyek például a System.Collections.Generic
névtéren belül vannak definiálva.
Objektumorientált programozás
[szerkesztés]Az F# nyelvben a többi CLI nyelvhez hasonlóan van lehetőség a CLI típusok és objektumok használatára.
Az osztályok az objektumorientált F# egyik legfontosabb építőelemei. Az osztályok a C# osztályokhoz hasonló tulajdonságokkal rendelkeznek: származhatnak ősosztályokból, elrejthetik a belső állapotukat, lehet konstruktoruk és megvalósíthatnak interfészeket is.
Például itt egy osztály definíció, konstruktorral, amely nevet és egy kor értéket vár, valamint két tulajdonságot definiál:
type Szemely(nev : string, kor : int) =
member x.Nev = nev
member x.Kor = kor
Az osztály alapértelmezetten publikus. A hozzáférési módosító megadására a type
kulcsszó után van lehetőség.
Források
[szerkesztés]- ↑ F# Historical Acknowledgements. (Hozzáférés: 2016. február 17.)
- ↑ Don Syme: F# 1.0.8 released. Microsoft. (Hozzáférés: 2014. szeptember 7.)
- ↑ Don Syme: F# 2.0 released as part of Visual Studio 2010. Microsoft. (Hozzáférés: 2014. szeptember 7.)
- ↑ Jason Zander: Visual Studio 2012 and .NET Framework 4.5 released to the web. Microsoft. (Hozzáférés: 2014. szeptember 7.)
- ↑ Visual Studio 2013 released to web. Microsoft. (Hozzáférés: 2014. szeptember 7.)
- ↑ Announcing the RTM of Visual F# 4.0. Microsoft. (Hozzáférés: 2015. szeptember 15.)
További információk
[szerkesztés]- F# dokumentáció a Microsoft oldalán (angol)
- F# fejlesztői csoport a Github oldalán (angol)
- F# kódrészletek (angol)