A Falcon programozási nyelv

Alprogramok

Szintaxis

A függvények olyan kódrészletek, melyek újrahasználhatók a számukra eltérő paraméterek megadásával. Formálisabban fogalmazva, a függvények olyan relációs operátorok, amik paraméterekhez kapcsolódnak, melyek lehetnek véges vagy végtelen paraméterek egyaránt. Az alábbi példa egy általános függvénydefiníciót mutat be:

function do_something( parameter ) printl( "Hey, this is a function saying: ", parameter ) end do_something( "Hello world" ) do_something( 15 ) /* again, ad libitum */

A function kulcsszóval deklaráljuk a függvényeket és az end kulcsszóval zárulnak le, melyet a függvény neve követ, majd 2 zárójel, melyek között adhatjuk meg a paramétereket. Ebben az esetben nincs visszatérési érték, de ez valójában egy illúzió. Igaz, hogy nincs valódi visszatérési érték, de ebben az esetben a nil speciális értékkel tér vissza a függvény. A függvények szeparáltan helyezkednek el a kódban, de összevegyíteni és szétszórtan elhelyezni is van lehetőségünk őket. Tehát a függvényeket a használatuk után is deklarálhatjuk, mint az alábbi példában is ez látható:

do_something( "Hello world" ) do_something( 15 ) function do_something( parameter ) printl( "Hey, this is a function saying: ", parameter ) end

Minden esetben nagyon fontos, hogy vizuálisan is gyorsan észlelhessük, hogy hol van a "valódi program", ezért szükséges a szeparálás.

/* This is my script */ do_something( "Hello world" ) do_something( 15 ) /************************************* Main section over, starting with functions. **************************************/ function do_something( parameter ) printl( "Hey, this is a function saying: ", parameter ) end

Ugyanez fordított elhelyezkedésben:

/* This is my script */ function do_something( parameter ) printl( "Hey, this is a function saying: ", parameter ) end /************************************* Main program begins here. **************************************/ do_something( "Hello world" ) do_something( 15 )

Ahogy az már más helyen is ismert, itt is van lehetőség egy soros statement-eket használni. A nyelv ezt a kettőspont operátorral valósítja meg.

A visszatérési értéket a return kulcsszóval tudjuk megadni, a más nyelveknél ismert módon. Példák ezekre:

function square( x ) y = x * x return y end

Ugyanez kettőspontokkal:

function square( x ): return x * x

A return parancsra hirtelen kilépünk az utasításból, visszaadjuk a megfelelő értéket, és az irányítás visszatér a hívó részhez. Például:

function some_branch( x ) if x > 10000 return "This number is too big" end /* do something */ return "Number processed" end

Ha egy kész függvényt meghívunk, de valamelyik paramétert nem töltjük ki, akkor az üres paraméter automatikusan nil-ként fog kiértékelődni. Tehát nem is szükséges épp ezen okból mindig kitölteni minden paraméter helyét.

Rekurzió

A nyelv támogatja a rekurziót, mely olyan függvényeket jelent, melyek önmagukat hívják meg a visszatérési lépésként, így egy látszólag végtelen lánc alakul ki, mely a kilépési feltétel teljesülésekor áll le.

function sum_of_first( x ) if x > 1 eturn x + sum_of_first( x - 1 ) end return x end

Lokális és globális változók

Lokális és globális változók egyaránt rendelkezésünkre állnak, használatuk a többi nyelvvel megegyező módon történik, ugyanúgy elfedik egymást, és minden ugyanúgy érvényes rájuk.

sqr = 1.41 function square( x ) sqr = x * x return sqr end number = square( 8 ) * sqr

A globális változók függvények segítségével is elérhetők, de normál esetben nem felülírhatók. Például:

sqr = 1.41 function square( x ) printl( "sqr was: ", sqr ) sqr = x * x return sqr end number = square( 8 ) * sqr
1.41

Néha az is hasznos lehet, ha egy külső változót akarunk megváltoztatni egy függvényből annak paraméterei nélkül. Ilyenkor a külső változó importálásához a global kulcsszót használjuk. Például:

function square_in_z( x ) global z z = x * x end z = 0 square_in_z( 8 ) printl( z ) // 64

Statikus változók

A falcon nyelvben lehetőség van statikus inicializációra, mely során amitiylen módon inicializáltunk, egyszer kiértékelődik és a memóriában marad későbbi használat esetére. Ugyanúgy megoldhatók azok a problémák melyekhez statikus inicializációt használnánk globális deklarációval, azonban az nagyon veszélyes és egyáltalán nem elegáns megoldás.

function say_something() static data = [ "have", "a", "nice", "day" ] current = 0 end if current == len( data ) return end element = data[current] current += 1 return element end thing = say_something() while thing != nil print( thing, " " ) thing = say_something() end printl()

Ahogy az imént is láthattuk, a static-end blokk segítségével valósítható meg. A blokk beljesében deklaráltak mind static-ok lesznek.

Begyáazott és névtelen függvények

Normál esetben a függvények top-level statement-ek. Egy függvény szülője csak egy falcon modul lehet. Az innerfunc kulcsóval lehet beágyazott függvényt definiálni egy függvényen belül. Egy lokális vagy globális változó értékeként definiálhatjuk a beágyazott függvényeket, és az end kulcsszóval zárul le a blokk. Példák:

var = innerfunc ( [param1, param2, ..., paramN] ) [static block] [statements] end
square = innerfunc ( a ) return a * a end printl( "Square of 10: ", square( 10 ) )

A névtelen függvény lehet beágyazott függvény is. Például:

function test( a ) if a == 0 res = innerfunc ( b, c ) // nested anonymous function! l = innerfunc ( b ) return b * 2 end result = b * l(c) + 1 return result end else res = innerfunc ( b, c ); return b * c -1; end end return res end

A névtelen függvények az automatizált folyamatok tervezéséhez nagyon szükségesek. Folyamatok által is képezhetünk automatikusan névtelen függvényeket, és minden névtelen függvényt ugyanúgy használhatunk szinte úgy, mint egy átlagos függvényt, kivéve hogy változón keresztül hívhatóak meg.

Függvények bezárása

Az end kulcsszó segítségével lehetséges a függvények lezárása. Egy end csak a hozzá lokálisan tartozó blokkot zárhatja le, a felette álló magasabb rendűt nem.

function makeMultiplier( operand ) multiplier = function( value ) return value * operand end return multiplier end m2 = makeMultiplier( 2 ) // ... by 2 > m2( 100 ) // will be 200 m4 = makeMultiplier( 4 ) // ... by 4 > m4( 100 ) // will be 400
function makeMultiplierGlobal() global globalFactor g = globalFactor // repeat locally multiplier = function ( value ) return value * g end return multiplier end globalFactor = 2 m2 = makeMultiplierGlobal() // ... by 2 > m2( 100 ) // will be 200 globalFactor = 4 m4 = makeMultiplierGlobal() // ... by 4 > m4( 100 ) // will be 400

A belső és névtelen függvények ebben az esetben csak kifejezések, az első példa ilyen formában írva:

function makeMultiplier( operand ) return ( function ( value ); return value * operand; end ) end

Vegyük észre, hogy itt jelen van a sorok végén egy extra pontosvessző, mivel egy nyitott zárójel esetében a sorvég nem tekinthető lezáróként többé, ezért van szükség pontosvesszőre. Ugyanez egy sorba írva:

function makeMultiplier( o ): return ( function (v); return v * o; end )

Kódblokkok

A kódblokkok legfőképp a névtelen függvények segítségére vannak, különösen azokéra, amiknek szüksége van egy kifejezésre, és visszaadja annak az értékét. A lambda kifejezés formális deklarációja:

block = { [p1, p2..., pn] => expression } // or block = { [p1, p2..., pn] => statement ... }

ahol p1...pn egy opcionális listája a paramétereknek. Az aktuális paraméterértékeket a függvényhívó operátorokon keresztül "táplálhatjuk". Például számok összegét jóval bonyolultabb módon is kiírathatjuk:

printl( {a, b => a + b}(2,2) )

A kódblokkok több mint egy egyszerű kifejezést tartalamznak, és ezek teljesen megegyeznek a névtelen függvényekkel. Ugyanúgy mint a névtelen függvények, itt is szükség van visszatérési értékre, hogy láthatóvá tegyük a hívó részére azt. Például:

posiSum = { a, b => val = a + b if val < 0: return -val return val } > posiSum( -5, 1 ) // 4 > posiSum( 5, 1 ) // 6

Futtatható tömbök

Amikor egy tömb első eleme egy függvény, a tömb hívhatóvá válik. A függvényt így a tömb első elemeként érhetjük el, ugyanúgy, mint ahogy az normál esetben egy teljesen átlagos elem lenne. A tömb első utáni elemei ez esetben a függvény paraméterei, illetve a függvény paraméterezésében is megadhatjuk a függvény elemeit.

printl( "Hello world" ) [printl]( "Hello world" ) [printl, "Hello"]( " world" ) [printl, "Hello", " ", "world"]()

Még egy érdekes használata a tömbök függvényként való használatának az előre cache-elt paraméterek. Ezeket előre tároljuk a tömbben referencia alapján, és így használhatóak fel későbbi műveletekhez.

i = 0 icall = .[printl $i ": "] for i in [0:10]: icall( "Looping..." )

Itt a $i az i értékhez tartozó referencia.