A veremmel való zsonglőrködés rövid szavaknál rendben van. Ha viszont egy szónak több bemenete van, és ezekre név szerint kell hivatkoznod, a Factor lokálisokat kínál: névvel ellátott kötéseket, amelyeket a :: (szódefiníciókhoz) vagy a [| | ] (beágyazott lambdákhoz) vezet be.
:: ( inputs -- outputs )Cseréld le a :-t ::-ra, és a bemeneti nevekből lokális változók lesznek a törzsben:
USING: locals ;
:: hypotenuse ( a b -- c )
a a *
b b *
+ sqrt ;
Hasonlítsd össze a veremrendezgetős változattal:
! DOCTEST: SKIP (shown for comparison — would re-define hypotenuse)
: hypotenuse ( a b -- c )
[ sq ] bi@ + sqrt ;
Mindkettő helyes. A lokálisok akkor a leghasznosabbak, ha egy bemenetre többször hivatkozol, vagy ha a műveletek sorrendje nem esik egybe természetesen a verem sorrendjével.
:> segítségévelA ::-tal létrehozott törzsben (vagy egy beágyazott [| ... |] lambdában) a :> levesz egy értéket az adatveremről, és egy friss lokálishoz köti:
value :> name ! immutable binding
value :> name! ! mutable binding (name! is its setter)
A változtathatatlan forma a gyakoribb: ezzel nevezhetsz el egy köztes értéket, hogy a törzs fentről lefelé olvasható legyen:
USING: locals math ;
:: average-3 ( x y z -- avg )
x y + z + :> sum
sum 3 / ;
A ! végződés módosíthatóként deklarálja a lokálist; a törzs későbbi részében a value name! (kettőspont és :> nélkül) új értéket ad neki:
USING: kernel locals math math.order ;
:: clamped ( x lo hi -- y )
x :> v!
v lo < [ lo v! ] when
v hi > [ hi v! ] when
v ;
A módosítható lokálisok azokban az iterációs szavakban hasznosak igazán, amelyekkel a későbbi feladatokban találkozol (pl. while).
[let - scope bárhonnanA :> csak lexikális scope-on belül működik, amit a :: és a [| ... |] automatikusan létrehoz. Ha egy sima :-os szóból vagy a listenerből szeretnél lokálisokat bevezetni, csomagold a kódot [let ... ]-be:
[let code :> name code :> name ... body ]
Minden :> name az előző kifejezés verem tetején lévő értékét köti; a kötések a forma további részében is láthatók.
USING: locals math ;
[let 3 :> x 4 :> y x x * y y * + ] . ! => 25
A [let a híd a veremstílusú :-os definíciók és a névvel ellátott kötések között. Kényelmes, amikor egy szónak csak egy szelete profitál a lokálisokból.
[| inputs | body ]
Egy quotation belsejében a [| inputs | body ] olyan lokálisokat vezet be, amelyekre a törzs név szerint hivatkozhat. Ez különösen hasznos magasabb rendű szavaknál, például az assoc-map-nél, ahol a quotation a key és a value értéket is megkapja:
USING: assocs locals ;
H{ { "a" 1 } { "b" 2 } }
[| key value | key value neg ] assoc-map .
! => H{ { "a" -1 } { "b" -2 } }
Ugyanez a forma működik a map-index-nél is (a [sequences][sequences] szókészletben), amelynek a quotationje az elemet és annak indexét is megkapja. A nevek világossá teszik, melyik operandus milyen szerepet játszik:
USING: locals sequences ;
! Divide each element by its 1-based position:
{ 10 80 270 } [| elt i | elt i 1 + / ] map-index .
! => { 10 40 90 }
A lambda veremhatását a bemeneti lista és a törzs által előállított értékek határozzák meg.
Akkor nyúlj a lokálisokhoz, ha:
dup/swap/rot nehezen olvasható.assoc-map-nél).Ha a törzs tiszta, lineáris folyam, a sima :-os definíciók rövidebbek és legalább olyan olvashatók maradnak.
assoc-map - egyszerre egy bejegyzésAz assoc-map (a assocs szókészletben) egy quotationt futtat le egy asszociatív gyűjtemény minden egyes bejegyzésén:
assoc-map ( assoc quot: ( key value -- newkey newvalue ) -- newassoc )
A quotation megírásának legtisztább módja egy lokálisokat használó lambda.
cond újraAmikor f vagy egy számérték alapján kell elágaznod, a cond pont a megfelelő forma. Nem kell case, mert nincs egyetlen érték, amihez hasonlíthatnál.
Megint a konyhában vagy, és tovább finomítod a lasagne receptjét a Leah ínycsiklandó lasagnéja feladatból. Az itteni részfeladatokban egyszerre több bemenettel kell zsonglőrködnöd, és pont ilyenkor jönnek jól a locals, a Factor névvel ellátott kötései.
Definiáld a cooking-status szót úgy, hogy kivegyen egy időzítőértéket a veremről, és egy állapotot leíró stringet adjon vissza.
0 → "Lasagna is done."
f (az időzítőt sosem állítottad be) → "You forgot to set the timer."
"Not done, please wait."
12 cooking-status . ! => "Not done, please wait."
0 cooking-status . ! => "Lasagna is done."
f cooking-status . ! => "You forgot to set the timer."
Definiáld a preparation-time szót úgy, hogy kapjon egy tömböt a rétegek neveivel és a rétegenkénti átlagos percszámot, majd adja vissza a teljes előkészítési időt.
{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } 3 preparation-time .
! => 18
Definiáld a quantities szót úgy, hogy kapjon egy tömböt a rétegek neveivel, és két értéket adjon vissza: a szükséges tészta grammját (tésztarétegenként 50 g) és a szükséges szósz literjét (szószrétegenként 1/5 liter).
{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } quantities .s
! => 100
! => 2/5
A barátod küld egy listát az összetevőkről, és a legutolsó elem a titka. Definiáld az add-secret-ingredient szót úgy, hogy kapja meg az ő listáját és a tiédet, majd adja vissza a te listádat a titkos összetevővel a végén.
{ "noodles" "sauce" "mozzarella" "kampot pepper" }
{ "noodles" "meat" "sauce" "mozzarella" }
add-secret-ingredient .
! => { "noodles" "meat" "sauce" "mozzarella" "kampot pepper" }
A szakácskönyv receptje két adagra elég. Definiáld a scale-recipe szót úgy, hogy kapjon egy receptet (egy hashtable-t, amely az összetevő nevéhez rendeli a mennyiséget) és a cél adagszámot, majd adjon vissza egy új, megfelelően átméretezett receptet.
H{ { "noodles" 200 } { "sauce" 1/2 } { "mozzarella" 1 } { "meat" 100 } }
4 scale-recipe .
! => H{ { "noodles" 400 } { "sauce" 1 } { "mozzarella" 2 } { "meat" 200 } }
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Factor nyelvet 47 fogalom163 feladat segítségével, valódi emberi mentorálással, mindez ingyen.