Kurzusok
/
Factor
Factor
/
Feladatok
/
Jelsablonok
Jelsablonok

Jelsablonok

Tanulófeladat

Bevezetés

A quotationt már tudod darabokból összerakni és lefuttatni. A quotation nem más, mint kódsorozat, ezért az ismert sorozatkezelő szavak is alkalmazhatók rá:

USING: kernel math prettyprint quotations sequences ;

{ [ 1 ] [ 2 + ] [ 3 * ] } concat >quotation call .   ! => 9
[ 1 + ] dup append .                                 ! => [ 1 + 1 + ]

Az append két quotationt fűz össze, a concat kilapítja a belőlük álló tömböt, a map adatokból készít quotationt, a >quotation pedig hívhatóvá teszi az eredményt. A MACRO: pontosan ezt a tudást veszi és viszi át fordítási időbe.

Mi az a makró

A MACRO: definíció úgy néz ki, mint egy közönséges szó, a törzse azonban aközben fut le, amikor a programodat fordítják, nem futás közben. A törzsnek egy quotationt kell a vermen hagynia. A fordító ezután befűzi azt a quotationt a hívás helyére: a makróhívást arra a kódra cseréli, amit a törzs előállított. Futásidőben már nem marad makró, csak a generált kód.

USING: kernel macros sequences ;

MACRO: twice ( quot -- spliced )
    dup append ;

Bárhol leírod, hogy [ 1 + ] twice, a fordító a következőt teszi:

  1. lefuttatja a törzset úgy, hogy [ 1 + ] van a vermen,
  2. a dup append felépíti a [ 1 + 1 + ] quotationt,
  3. beilleszti a kódját, 1 + 1 +-t, arra a helyre.

Így egy olyan szó, amely a twice-t hívja, úgy fordul le, mintha kézzel írtad volna le, hogy 1 + 1 +:

: inc-twice ( x -- y ) [ 1 + ] twice ;

5 inc-twice .   ! => 7

A kulcsfontosságú különbség: egy közönséges szó, amely quotationt kap, futásidőben call-olja azt. A makró soha nem hív meg semmit: új kódot ad a fordítónak, hogy az a helyére fordítsa.

A bemeneteknek literáloknak kell lenniük

Mivel a törzs fordítási időben fut le, a makró bemeneteit már akkor ismerni kell. A hívás helyén literáloknak kell lenniük: egy [ … ] quotation, egy szám, egy tömb, egy string. Egy olyan értéket, amely csak futásidőben létezik, nem lehet átadni egy makrónak.

! DOCTEST: SKIP — illustrative call sites, not standalone code
[ 1 + ] twice          ! ok: the quotation is a literal
[ 1 + ] 3 repeat-quot  ! ok: the quotation and the number are literals

Az eszköztár

A makró törzse közönséges kód, amely egy quotationt ad vissza. A munka nagy részét olyan szavak végzik el, amelyekkel már találkoztál:

mit építs… mivel
[ A B ] a [ A ]-ből és [ B ]-ből append
egy quotation a belőlük álló tömbből concat >quotation
egy quotation a sorozat minden eleméből map, majd concat >quotation

A készletet két további szó egészíti ki, a sequences és a kernel szókészletből.

A <repetition> (a sequences szókészletben) egy elem n példányából álló sorozatot készít. A veremhatása ( length elt -- repetition ): a darabszám jön először. Az eredmény virtuális sorozat, ezért a szokásos módon lapítsd ki:

3 [ 1 + ] <repetition> concat >quotation .   ! => [ 1 + 1 + 1 + ]

A curry (a kernel szókészletben) egy értéket fűz a quotation elé, és olyan új quotationt készít, amely először azt az értéket teszi a veremre:

3 [ + ] curry .          ! => [ 3 + ]
{ 1 2 3 } [ . ] curry .  ! => [ { 1 2 3 } . ]

A curry az, amivel egy konkrét elemet beégetsz egy quotationbe: pontosan ez alakítja a { 10 20 30 } tömböt és a [ + ] quotationt [ 10 + ] [ 20 + ] [ 30 + ]-vá.

Miért egyszerűbb ez, mint amilyennek hangzik

Néhány nyelvben a makrókhoz különleges quote/unquote szintaxis és további gépezet kell a névütközések elkerüléséhez. A Factorban erre semmi sem kell: a quotation már feloldott szavak sorozata, mert a parser már akkor megkereste az egyes dup, + és append szavakat, amikor beolvasta a [ … ]-t. A makró törzse tehát nem más, mint a szokásos sorozatkezelés, amely épp egy quotationt ad vissza.

Közeli rokon: $[ … ]

Egy makró quotationt ad vissza, hogy befűződjön egy hívásba. Ha viszont egy egyszerű értéket szeretnél számítani elemzési időben, a $[ code ] lefuttatja a code-ot, amikor a fájlt olvassák, és az eredményt literálként beolvasztja a forrásba:

! DOCTEST: SKIP — compile-time value, shown for contrast
USING: calendar literals ;

CONSTANT: build-time $[ now ]

A $[ … ] a literals szókészletből származik, amely az elemzési idejű eredmények literálokba való beillesztéséhez tartozó szavakat gyűjti össze. A teljesség kedvéért említjük. A négy sablon, amelyet meg fogsz írni (twice, repeat-quot, compose-many és each-literal), mind MACRO: deklaráció.

Utasítások

Egy jelzőállomás kódgeneráló eszközkészletét gondozod. Minden makró egy sablon: egy kis minta, amellyel a fordító minden hívási helyen speciális kódot állít elő.

Te csak a négy makrót írod meg. A tesztfájl apró burkoló szavakat definiál, amelyek meghívják a makróidat (egy makrót csak a generált kódon keresztül lehet megfigyelni), majd ellenőrzi a burkoló szavak futásidejű eredményeit. A burkoló szavakat hagyd úgy, ahogy vannak.

Minden részfeladatnál a törzs a hívási hely literál bemeneteit kapja meg a vermen, és egy quotation maradjon utána. A »compiles to« sorok mutatják meg azt a lineáris kódot, amelyet a quotationnek elő kell állítania.

1. Kétszer egymás után

A twice egy literál quotationt kap, és olyan quotationt ad vissza, amely az eredetit kétszer egymás után futtatja.

! : inc-twice ( x -- y ) [ 1 + ] twice ;
! body receives [ 1 + ]  ->  must build [ 1 + 1 + ]
5 inc-twice .   ! => 7

2. N ismétlés

A repeat-quot egy literál quotationt és egy literál n számot kap, és olyan quotationt ad vissza, amely az eredetit n-szer futtatja egymás után. n = 0 esetén az üres quotationt adja vissza: [ ].

! : inc-thrice ( x -- y ) [ 1 + ] 3 repeat-quot ;
! body receives [ 1 + ] 3  ->  must build [ 1 + 1 + 1 + ]
5 inc-thrice .   ! => 8

3. Több összefűzése

A compose-many egy literál tömböt kap, amely quotationokat tartalmaz, és egyetlen quotationt ad vissza, amely sorban lefuttatja mindegyiket. Üres tömb esetén az üres quotationt adja vissza.

! : pipeline ( x -- y ) { [ 1 + ] [ 2 * ] [ 1 - ] } compose-many ;
! body receives { [ 1 + ] [ 2 * ] [ 1 - ] }  ->  must build [ 1 + 2 * 1 - ]
5 pipeline .   ! => 11

4. Kigöngyölt iteráció

Az each-literal egy literál sorozatot és egy quotationt kap. Olyan quotationt ad vissza, amely a sorozat minden eleménél a veremre teszi az adott elemet, majd lefuttatja a quotationt. Az iteráció így fordítási időben zajlik le, ezért a generált kód lineáris.

! : sum-three ( -- n ) 0 { 10 20 30 } [ + ] each-literal ;
! body receives { 10 20 30 } [ + ]  ->  must build [ 10 + 20 + 30 + ]
sum-three .   ! => 60

Ez a négy közül a leginkább szerkezeti jellegű: a generált kódot egyszerre alakítja a sorozat hossza és az elemeinek értékei. A tippek lépésről lépésre végigvezetnek az összeállításán.

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
Factor Exercism

Készen állsz elkezdeni a(z) Jelsablonok feladatot?

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.