Go to the first, previous, next, last section, table of contents.


Makroi

.macro

.MACRO procname :input1 :input2 ...		(specialna forma)
.DEFMACRO procname text

Macro je specijalni oblik procedure ciji se output evaluira kao Logo instrukcije u kontekstu one procedure koja je pozvala macro. .MACRO je upravo kao TO, osim sto nova procedura postaje macro; .DEFMACRO je upravo kao DEFINE sa istim izuzetkom.

Macro-i su korisni pri pisanju novih kontrolnih struktura usporedivih sa REPEAT, IF, itd. Takove kontrolne strukture mogu gotovo, ali ne sasvim biti duplicirane sa obicnim Logo procedurama. Na primjer, ovdje je obicna proceduralna verzija REPEAT:

to my.repeat :num :instructions
if :num=0 [stop]
run :instructions
my.repeat :num-1 :instructions
end

Ova verzija radi dobro za vecinu upotreba, na primjer,

my.repeat 5 [print "hello]

Ali ne radi ako instrukcije sadrze OUTPUT, STOP, ili LOCAL. Na primjer, pogledajte slijedecu proceduru:

to example
print [Guess my secret word.  You get three guesses.]
repeat 3 [type "|?? | ~
    if readword = "secret [pr "Right! stop]]
print [Sorry, the word was "secret"!]
end

Ova procedura radi kako je napisana, ali ako upotrijebimo MY.REPEAT umjesto REPEAT, nece raditi zato sto ce STOP zaustaviti MY.REPEAT umjesto da zaustavi EXAMPLE.

Rjesenje je da napisemo MY.REPEAT kao macro. Umjesto da samostalno izvrsi instrukcije, macro vraca listu Logo instrukcija. Sadrzaj te liste se evaluira kao da se one pojavljuju umjesto poziva macro-a. Ovdje je macro verzija REPEAT:

.macro my.repeat :num :instructions
if :num=0 [output []]
output sentence :instructions ~
    (list "my.repeat :num-1 :instructions)
end

Svaki macro je operacija -- uvijek mora nesto outputirati. Cak i u baznom slucaju (base case, ili stop linija), my.repeat outputira praznu listu instrukcija. Da pokazemo kako my.repeat radi, uzmimo primjer:

my.repeat 5 [print "hello]

Za ovaj ce primjer, my.repeat outputirati slijedecu instruction listu

[print "hello my.repeat 4 [print "hello]]

Logo ce tada izvrsiti te instrukcije umjesto originalnog poziva my.repeat: time se ispise hello jednom i pozove se jos jedna repeticija.

Tehnika upravo pokazana, iako jednostavna za razumijevanje, sporo radi jer svaka repeticija mora ponovo konstruirati listu instrukcija. Drugi pristup je definirati my.repeat kao macro koji radi kao ne-macro verzija, osim ako instrukcije sadrze OUTPUT ili STOP:

.macro my.repeat :num :instructions
catch "repeat.catchtag ~
    [op repeat.done runresult [repeat1 :num :instructions]]
op []
end

to repeat1 :num :instructions
if :num=0 [throw "repeat.catchtag]
run :instructions
.maybeoutput repeat1 :num-1 :instructions
end

to repeat.done :repeat.result
if emptyp :repeat.result [op [stop]]
op list "output quoted first :repeat.result
end

Ako instrukcije ne sadrze STOP ili OUTPUT, onda ce REPEAT1 doci do svog base case i pozvati THROW. Kao rezultat, zadnja linija my.repeat-a ce outputirati praznu listu, tako da slijedeca evaluacija macro rezultata nece napraviti nista. Ali ako se dese STOP ili OUTPUT, tada ce REPEAT.DONE outputirati STOP ili OUTPUT instrukciju, koje ce biti izvrsene u kontekstu procedure koja je pozvala macro.

Komande koje definiraju macro pocinju sa tockom jer su macro-i napredne funkcije Loga; lako se zapadne u probleme definirajuci macro koji ne zavrsava, ili nepravilno konstruira listu instrukcija.

Za razliku od LISP-a macro-i u Logu nisu specijalna forma. To jest macro se evaluira normalno, kao i bilo koja druga Logo procedura. Samo je output od macro-a taj sa kojim se radi drugacije.

Ovdje je jos jedan primjer:

.macro localmake :name :value
output (list "local ~
    word "" :name ~
    "apply ~
    ""make ~
    (list :name :value))
end

Upotrebljava se ovako:

to try
localmake "garply "hello
print :garply
end

LOCALMAKE outputira listu

[local "garply apply "make [garply hello]]

Razlog za upotrebu APPLY je da ne moramo odlucivati da li drugi input od MAKE treba qvotirati ili ne. (U ovom slucaju bi trebalo -- MAKE "GARPLY "HELLO -- ali navodnici "qvotiranje" bi bilo pogresno ako bi drugi input bio lista.)

Cesto je uputno upotrijebiti ` funkciju za konstruiranje liste instrukcija:

.macro localmake :name :value
op `[local ,[word "" :name] apply "make [,[:name],[:value]]]
end

Sa druge strane, ` je prilicno spor, jer je tree (drvo - duboko) rekurzivan i napisan u Logu.

See section to ; section define ; section apply ; section stop ; section output

.defmacro

See section .macro

macrop

MACROP name
MACRO? name

outputira TRUE ako je input name ime macro-a.

macroexpand

MACROEXPAND expr				(library procedura)

uzima kao input Logo izraz koji poziva macro (tj., izraz koji pocinje sa imenom macro-a) i outputira Logo izraz u koji bi macro preveo inputirani izraz.

.macro localmake :name :value
op `[local ,[word "" :name] apply "make [,[:name] ,[:value]]]
end

? show macroexpand [localmake "pi 3.14159]
[local "pi apply "make [pi 3.14159]]


Go to the first, previous, next, last section, table of contents.