A Factor programozási nyelv

Típusok, típuskonstrukciók

Típusszerkezet

A Factor egy alapvetően objektumelvű nyelv, dinamikus tipusozással. A változóknak és a stack effektben deklarált neveknek nem kell megadnunk a típusát, valamennyien az object osztály leszármazottai és a Forth-stílusú korai stack-alapú nyelvekkel ellentétben a vermen nem csak egyszerű (például 16 bites) adatok lehetnek, hanem tetszőleges osztályú/típusú adat, sőt mint azt látni fogjuk akár futtatható kód is.
Nincsenek igazán megkülönböztetett alaptípusok, pontosabban más értelemben vannak, ugyanis például a lebegőpontos és egész számok ugyanúgy elemei logikailag az objektumhierarchiának, de nem kell külön szótárat betölteni, ha használni szeretnénk a számokat. Bizonyos számliterálokat tehát például mindenfajta USE: nélkül használhatunk(ez alól a komplex számok és hasonlók se kivételek), más kérdés, hogy a rajtuk végzett műveletek nem feltétlen lesznek elérhetőek - például a + művelet a math szótárban található meg. Az itt említettek miatt érdemes tehát bizonyos értelemben elemi típusokról beszélni, de ezek a típusok is bele vannak foglaltatva az objektumhierarchiába. A fenti szép képből talán azért egy kicsit ki tudnak lógni a szavak, mert ott kicsit nehézkes és ködös eldönteni, hogy egyáltalán részei-e a hierarchiának és ha igen, akkor hogyan kapcsolódnak hozzá. A szavaknak lehetnek property-jei ugyanis és több szempontból viselnek bizonyos objektumelvű szemlélettel kialakított tulajdonságokat, mégis jobb inkább valamiféle két szinten működő objektumelvűségről beszélni és logikailag elkülöníteni őket az implementált típusrendszertől.

Elemi típusok

Logikai értékek

Factorban létezik egy f singleton false érték és a nyelv konvenciója szerint ez jelképezi a false-ot, minden más objektum pedig igaz logikai értéket képvisel. Az f, vagyis false értéke egy nagyon alacsonyszintű dolog, gyakorlatilag egy osztály és egy objektum is egyben. A logikai kifejezések használatát megkönnyítendő a Factorban defniáltak egy t szót is(szintén egyben osztály is), ami viszont magasabb szinten helyezkedik el a programozási nyelv felépítésében. Az f és a t osztályok unióosztálya képezi a boolean típust, tehát maga a boolean a factorban már nem igazán tekinthető alaptípusnak, helyette az a fura helyzet áll elő, hogy ezt a szerepet az f látja el.
A fent szavakkal leírt jelenséget érzékeltetni a legjobban talán néhány példával lehet:

USE: classes ! A class szóhoz kell f . ! Itt most az f objektumra hivatkozunk, eredmény: f \ f . ! Ezzel a módszerrel megkaphatjuk f osztályát, eredmény: POSTPONE: f f \ f eq? . ! Referenciaként azonos-e f és f osztálya? Eredmény: f (ez már az összehasonlítás miatti false tehát nem) f \ f = . ! f és az f osztálya két különböző objektum, ezért az eredmény: f (az összehasonlítás miatti false) { f } ! ez egy tömböt tesz a stack-re, amiben az f objektum van { POSTPONE: f } ! ez egy tömböt tesz a stack-re, amiben az f osztály van POSTPONE: f ! stack underflow: ez viszont már nem megy... f class . ! Kiírjuk az f osztályát, eredmény: POSTPONE f \ f class . ! Kiíratjuk az f osztályának az osztályát, eredmény: word t \ t eq? . ! Ugyanaz-e t és \ t ? Eredmény: t, vagyis referencia szerint igen! t \ t = . ! Nyilván ez is t eredményt ad

Számok

A Factor nyelv törekedni próbál arra, hogy lehetőleg a számok kezelésekor minél pontosabban tudja követni a matematikában megszokott szemantikát. Például két nagy szám szorzása sose csorduljon túl és két egész szám osztásakor keletkező eredmény ábrázolható racionális tört legyen. A nyelv a fentieken kívül támogat lebegőpontos és komplex számokat is. A számokon dolgozó szavak legtöbbje a math szótárban található. Factorban bizonyos számtípusokra igazak bizonyos implicit konverziós szabályok, ezeket a megfelelő szekcióban ismertetjük, a számliterálok alakja és fajtáu pedig az előző fejezetben már ismertetésre kerültek.

Általános szám-műveletek(alapműveletek)

Minden számra értelmezettek a +, -, *, / műveletek, a nem-kommutatívak ezek közül balról jobbra működnek, intuitív módon (20 4 / . 5-öt ad eredményül) és valós számokra értelmezettek a szokásos <, >, <=, >=, műveletek is, komplexekre természetesen csak az egyenlőség működik. Ezen felül van még egy number= szó is, mely kvésbé precíz eredményt ad, de a number únióosztály felett van definiálva, így alkalmas különböző típusú értékek közötti vizsgálatra is. Float értékek esetén előfordulhat, hogy a megvizsgálandó számok legalább egyike NaN(Not a Number). Ilyenkor a hagyományos relációműveletek és egyenlőségvizsgálat kivételt generál, ha ezt el szeretnénk kerülni, akkor egyenlőség helyett number=-t használjunk(ha NaN előfordul, mindig false-t ad vissza 'NaN NaN number= .' esetén is f!) illetve a relációs szavak u-s(unordered) változatait, például u<. Az itt leírtakat úgy is nevezik, hogy number protokoll, ugyanis a nyelv számaiból(racionális és komplex számaiból, ahol racionálisba tartozó a ratio a fixnum és a bignum is) képeztek egy number únióosztályt.

FONTOS: A nullával való osztás szemantikája platform és adattípusfüggő

Egyéb szám-műveletek és egyéb számok

A fenti egyszerű alapműveleteken kívül lehetőség van sok, típusspecifikus művelet elvégzésére is, például moduló-aritmetika, bitműveletek komplex műveletek stb. Ezeknek a nagy része szintén a math (esetleg math.akármi.akármimás stb.) szótárban található meg. Könyvtári kiterjesztésként a fentieken kívül dolgozhatunk egyébként még kvaterniókkal is.

Típuskonstrukciók

Factorban kifejezetten sok előre definiált konkrét és absztrakt (osztályunió, vagy mixin class) kollekció osztály létezik, melyeket felhasználhatunk. A nyelv összes típuskonstrukciójának részletes bemutatása helyett mi most csupán átfogó képet szeretnénk nyújtani a lehetőségekről.
A típuskonstrukciók logikailag a következő módon szervezhetőek:

Szekvenciatípusok

A szekvenciák véges, lineárisan rendezett gyűjteményei elemeknek. A szekvenciákkal dolgozó szavakat a sequences szótár tartalmazza.

A szekvenciatípusba tartozó típusok implementálnak egy protokollt, vagyis a következő műveleteket implementálnunk kell:


Ezen felül egyéb opcionális műveletek is vannak, például set-lenght is megadható, ha átméretezhető a szekvenciánk, vagy megadható pl. like művelet, mely két szekvenciatípusból egy harmadikat csinál úgy, hogy a keletkező szekvencia az első paraméter adatait tartalmazza, de a második paraméternek megfelelő kanokikus típussal.

Szekvenciatípusok például:


Átméretezhető szekvenciák(growable):

Az egyszerű szekvencia protokollt megvalósító osztályok felett sok ismert művelet definiált, ezeket szekvenciakombinátoroknak nevezik és a sequences szótárban helyezkednek el. Minden szekvencia típusú objektumra értelmezett például a funkcionális nyelvekből jól ismert map függvény, a reduce (ami más nyelvek fold-jának felel meg), az accumutate (ami részeredményeket is gyűjtő fold), a filter és egyszerű lekérdezések, mint például az all? és az any? szavak. Ezek funkcionális szemléletű szavak, de van a legtöbbjüknek helyben dolgozó változata is, ami nem új értéket állít elő, hanem a már meglévőt változtatja (kivéve ha az mutable). Ez utóbbi szavak az előzőek felkiáltójellel ellátott változatai, például a map! szó.
Elemenkénti feldolgozáshoz is kapunk beépített eszközt, az each, 2each, 3each személyében (2-es és 3-as változata egyébként a map-nek is van).

Fontos megjegyezni, hogy a tömbök, vektorok, egyéb szekvenciák általában nem kell, hogy homogén, egyazon-típusú elemekből álljanak. A legtöbb nyelvben ez nem így van(sok dinamikus nyelven sem), de itt a fenti szabályra vonatkozó kivételek a ritkábbak a könyvtári gyűjteményeknél (például Byte-tömb, Byte-vektor kivételesek, mert csak byteokat tartalmazhatnak, de { 1 "abc" 2.5 } tömb teljesen lehetésges). A legtöbb különleges esetet a literáloknál említettük, illetve a fejlesztőkörnyezet help-rendszerében rákereshetünk az egyes típusok esetén lehetséges-e a különböző típusú elemek sorozata.

Asszociáció típusok

Az asszociáció típusok kulcs-érték párokat absztrahálnak. A felettük definiált szavak az assocs szótárban vannak.

Az asszociáció típusoknak is implementálniuk kell egy protokollt, amely a következő:


Itt is vannak egyéb opcionálisan implementálható műveletek is(például az assoc-like).

Asszociatív típusok:


Asszociatív típusokra is vannak predefinit kombinátorok, például assoc-map a map megfelelője.

Egyéb típuskonstrukciók

A Factor nyelv sok egyéb ismert típuskonstrukciót nyújt számunkra, melyek halmaza folyamatosan bővül. Itt megemlítünk néhány ismertebbet közülük:


Külön stack viszont egyelőre nincs, ami nem azért van, hogy a nyelv beépített stackjét használjuk helyette, hanem mert a szekvenciákra megadták a stackműveleteket is: push, push-all, pop, pop* szavakkal.

Típuskonverziók

Általában adnak típuskonverziós szavakat a beépített szótári típusokhoz, ezek formája valami>másikvalami(esetleg az első valami elhagyásával), ha valami típusból, egy másikvalami típusra konvertál. A nyelvben ezeken kívül azonban vannak esetek, amikor implicit típuskonverzió történik. Ilyen történik például a számok esetében, ha különböző típusú elemekkel számolunk:

USE: classes 3 >fixnum 6 >bignum * class . ! Az eredmény: bignum, tehát a szorzat változtatta a típust, ha az egyik bignum volt ! 1/2 2.0 + . ! Az eredmény: 2.5, mert ha egy kifejezésben float szerepel, az eredmény float lesz ! C{ 1 2 } C{ 3 -2 } + . ! Eredmény: 4 (komplex számok "vissza-alakulhatnak" valóssá) C{ 0.0 2.0 } C{ 0.0 1.0 } * . ! Viszont nem minden esetben. Eredmény: C{ -2.0 0.0 }