Az F# programozási nyelv

Az F# ontológiái

Az ontológia

Jelen kontextusban ontológián egy speciális tudásábrázolási technikát értek. Egy közismert definíció szerint „az ontológia egy közös fogalomrendszer formális, explicit specifikációja”

Az ontológia készítéséről

Egy ontológia készítését a forrásanyagok kiválasztása előzi meg. Az F# nyelv esetén elsődleges forrásnak a – draft státuszú – specifikációt tekintettem. Először megpróbáltam elkészíteni a nyelv ontológiáját csak a vázlatos szabványra hivatkozva, de nem sikerült. Egyrészt a dokumentum egy egyszerű taxonómia készítéséhez sem tartalmaz elegendő mennyiségű és minőségű információt. Másrészt a fő hangsúlyt a nyelv szintaktikájára helyezi, miközben elhanyagolja a fontos F# fogalmak definícióját. A kifejezéseket gyakran nem kíséri magyarázat, olykor pedig több jelentésük is ismert. Mivel az F# draft specifikáció elégtelennek bizonyult, más megbízható forrást kellett keresnem. Választásom két szakkönyvre esett: Foundations of F# és Expert F#. Ezek a források azért tekinthetők megbízhatónak, mert szerzőik a nyelv tervezői és olyan személyek, akik szoros kapcsolatban állnak a nyelv fejlesztésével. Az így feldolgozott korpusz mennyisége összesítve 1156 nyomtatott oldal.

Az F# al-ontológiái

A fogalmakat két ontológiába csoportosítottam:

Az F# típusok ontológiája

Az F# a „típus” kifejezést négy különböző, ugyanakkor kapcsolódó értelemben használja. Az ontológiakészítés szempontjából ezen jelentések pontos szétválasztása lényegbevágó. A négy jelentés a következő:

  1. Típusdefiníció: Egy adott típus tényleges definíciója a .NET és F# könyvtárakban.
  2. Szintaktikai típus: A programszövegben előforduló típusok.
  3. Statikus típus: Az ellenőrzés és típuskövetkeztetés során használt típusok, átmenetet képeznek a szintaktikai és futásidejű típusok között.
  4. Futásidejű típusok: A típusdefiníciók és statikus típusok információinak futásidejű ábrázolásai.

Az F# típusok elemzésénél végig a statikus típusokra támaszkodom. A dolgozat további részében a „típus” kifejezésen a statikus típusokat értem.

Az ontológia készítése során az egyik legjelentősebb problémám az volt, hogy milyen elvek mentén csoportosítsam az F# típusokat. Felmerült például a funkcionális-imperatív, mutable-immutable, referenciatípus-értéktípus stb. csoportosítás. Mindegyik választással az a probléma, hogy a többi csoportosítás alapját képező tulajdonságokat is fel kell tüntetni a diagramon úgy, hogy az pontos legyen, de ugyanakkor átlátható maradjon. Kezdetben a Pickering által javasolt csoportosítás tűnt vonzónak:

The type system in F# provides a number of features for defining custom types. All of F#’s type definitions fall into two categories. The first category is types that are tuples or records. These are a set of types composed to form a composite type (similar to structs in C or classes in C#). The second category is sum types, sometimes referred to as union types. (p. 42)

Pickering szerint tehát az F# típusok alapvetően két csoportra oszthatók, az első kategóriába a tuple vagy rekord típus kerül, míg a másik csoportba az ún. szum típusok tartoznak, amit gyakran union típusnak is neveznek.

Ennek a megközelítésnek a legnagyobb hátránya, hogy nem ragadja meg a struct, union és record típusok közötti erőteljes hasonlóságot. Az említett típusok mindegyikének lehetnek tagjai (tulajdonságok és metódusok), implementálhatnak interfészeket és zártak (sealed), azaz nem specializálhatók. A közös vonások kiemelése érdekében bevezettem egy közös őst, az osztályszerű típust (class-like type), ami azt a tényt is tükrözi, hogy a struct kivételével ezek a típusok .NET osztály típusra fordítódnak.

Végül úgy döntöttem, az F# típusokat két nézet szerint csoportosítom. Az egyik a típusok szerkezetén, a másik az értéktípus-referenciatípus megkülönböztetésen alapszik.

Szerkezeti nézet

A .NET típusokat zöld háttérrel jelöltem. Ezeket nem fejtem ki a diagramon, részletekért lásd a .NET CLS ontológiát. MEGJEGYZÉS. Az F# osztálytípus a CLS objektumtípus megfelelője.


ontológia diagram 1

1. diagram. F# típusok ontológiája, szerkezeti nézet

Az áttekinthetőség kedvéért a Lista (List) típust külön diagramon mutatom be:


lista diagram 1

2. diagram. Az F# Lista típusa (az F# típusok ontológiájának részlete)


táblázat 1

1. táblázat. Az F# típusok ontológia fogalmai


táblázat 2

2. táblázat. Az F# típusok ontológia kapcsolatai

Megszorítások

  1. A discriminated union case nevek nagybetűvel kezdődnek.
  2. Az option típus értéke vagy egy v érték, Some(v), vagy annak hiánya, None: context OptionType inv: self.cases -> size() = 2 self.cases -> exists(c : Discriminator | c.name = 'None') self.cases -> exists(c : Discriminator | c.name = 'Some' and c.type -> size() = 1)
  3. Az osztályszerű (class-like) típusoknak nem lehet absztrakt metódusa: context ClassLikeType inv: self.methods -> forAll(isAbstract = false)
  4. A ref típus egyetlen változtatható mezőt tartalmaz, melynek neve „contents”, típusa változó típus: context RefType inv: self.fields -> size() = 1 self.fields -> exists(f : Field | f.name = 'contents' and f.mutable = true and f.type = VariableType)
  5. Egy kollekció minden eleme azonos típusú: context CollectionType inv: self.elements -> forAll(e1, e2 : Item | e1.type = e2.type)

Inkonzisztenciák

  1. Amint az a bevezetésben is elhangzott, az F# draft specifikáció nem tartalmaz elegendő információt egy hierarchia felépítéséhez. A CLS bizonyos szintű ismerete nélkül lehetetlen az alapján ontológiát készíteni.
  2. A metódus (method) kifejezés határozatlan használata. F# terminológiában a függvény szót részesítik előnyben, típustagoknál viszont a metódus szó gyakoribb. Ezt egyik irodalom sem részletezi.
  3. Az F# draft specifikáció a típusrendszer jellemzőit próbálja összefoglalni, azonban elég sikertelenül. Meglátásom szerint a szabványnak ez a legkevésbé konzisztens része, több okból is. Egyrészt egyik felsorolás sem sorolja fel az összes típust, mindegyik csak annak valamelyik részhalmazával foglalkozik. Másrészt az értéktípusok és referenciatípusok közötti megkülönböztetés nem teljes, mivel a felsorolás nem tesz említést az enum, absztrakt osztály, tömb, lista és változó típusokról. Az előzőleg említett egyik szakasz részben orvosolja ezt a problémát azáltal, hogy a korábban kimaradt típusoknak megemlíti az ősosztályát, amiből következtetni lehet jellegére. Ez alapján a tömbök és absztrakt típusok a referenciatípus kategóriába tartoznak, míg az enum értéktípus lesz, .NET terminológia szerint.
  4. Az interfész típus őse a System.Object. Ennek ellentmond az ECMA 8.9.11. és 8.6. szakasza: előbbi azt állítja, hogy az objektumtípusokkal ellentétben az interfészek nem alkotnak egyetlen öröklődési hierarchiát („Object types form a single inheritance tree; interface types do not.”), utóbbi szerint pedig interfész típus soha nem lehet osztálytípus, mivel nem tartalmaz teljes értékleírást („An interface type can never fully describe the representation of a value. Therefore an interface type can never support a class contract, and hence can never be a class type or an exact type.”).
  5. Immutable vs. mutable (változtatható ill. nem változtatható) típusok. A [3] és [8] ellentmondanak azzal kapcsolatban, hogy változtathatónak számít-e a rekord típus. [8] szerint egy rekord frissítése csak a mezők értékét frissíti, nem pedig magát a rekordot (59. o.), eszerint tehát a rekord nem változtatható. [3] ellenben azt állítja, hogy egy rekord változtathatónak tekintendő, ha legalább egyik mezője mutable címkével van ellátva (72. o.). Személyes álláspontom ezen a téren az utóbbi nézethez áll közelebb, vagyis ha a rekord tartalma megváltoztatható, akkor maga a rekord is megváltoztatható. MEGJEGYZÉS. [10] nem foglalkozik a kérdéssel.

Érték-referencia nézet

Ennél a nézetnél csak a diagramot ismertetem, mivel új fogalmakat nem vezet be. Az F# három értéktípust ismer, ezek az előredefiniált értéktípusok (pl. int, boolean stb.), az enumok és a struktúrák. Az összes többi típus a referenciatípusok közé sorolható.


ontológia diagram 2

3. diagram. Az F# típusok ontológiája, érték-referencia nézet


Inkonzisztenciák

Értéktípus vs. struct típus. Az F# draft az int típust struct típusnak tekinti: „we say int is a struct type because System.Int32 is a struct type.”. Az ECMA-335 nem említi a struct kifejezést az értéktípus szinonimájaként, a System.Int32-t a beépített értéktípusok között tartja számon. Az ECMA terminológia jellemzően az értéktípus kifejezést használja, míg az F# szakirodalom a struct (struktúra) szinonimával illeti az érték típusú szerkezeteket. Ezzel az a probléma, hogy a struct egyben a C-ből közismert rekord- szerű szerkezet elnevezése is egyben, ez pedig néhol félreértéshez vezethet. Javaslom, hogy a struct kifejezést az utóbbi értelemben használjuk.

F# változótípus megszorítások al-ontológia (F# generikusok)

A generikusokat F#-ban a típusváltozók jelképezik, melyek típusa kezdetben változó típus. A változótípusokra típusmegszorításokat alkalmazhatunk, melyek szűkítik a típusváltozó lehetséges értékeit. Az 4. diagram a típuskövetkeztetésnél használatos megszorításokat ábrázolja. A .NET kompatibilitás érdekében bevezetett megszorításokat zöld színnel jelöltem, a sárga hátterűek ritkán használatosak, az egyetlen tényleges használt megszorítás az altípus megszorítás, amit külön színnel emeltem ki. Az ábra jól mutatja, milyen kompromisszumokat kellett kötni a .NET interoperabilitás érdekében.


ontológia diagram 3

4. diagram. F# típusváltozó megszorítások



táblázat 3

3. táblázat. F# típusváltozó megszorítás fogalmai


MEGJEGYZÉS. A megszorítások között csak öröklődési kapcsolat áll fenn, ezeket az ábra tartalmazza, így további táblázatra nincs szükség.

Inkonzisztenciák

A struct kifejezés további félrevezető használata. Az F# draft korábbi szakasza által említett .NET Struct Constraint megszorítás akkor áll fenn, ha a típus, amelyikre vonatkozik, .NET értéktípus. Az jelent problémát, hogy a CTS nem definiálja a struct típust. Egyértelmű, hogy mivel a referenciatípussal van szembe állítva, itt az értéktípus értelemben használatos, a struct mégsem érvényes CTS típus.