Hvor langt kan LISP makroer gå?

stemmer
43

Jeg har lest mye som LISP kan omdefinere syntaks på fly, antagelig med makroer. Jeg er nysgjerrig på hvor langt dette faktisk gå? Kan du omdefinere språkstrukturen så mye at det borderline blir en kompilator for et annet språk? For eksempel kan du endre den funksjonelle natur LISP til en mer objektorientert syntaks og semantikk, kanskje si at syntaks nærmere noe som Ruby?

Spesielt er det mulig å bli kvitt parentes helvete ved hjelp av makroer? Jeg har lært nok (Emacs-) LISP å tilpasse Emacs med mine egne mikro funksjoner, men jeg er veldig nysgjerrig hvor langt makroer kan gå i å tilpasse språket.

Publisert på 05/08/2008 klokken 07:32
kilden bruker
På andre språk...                            


14 svar

stemmer
33

Det er et veldig godt spørsmål.

Jeg tror det er nyansert, men definitivt ansvarlig:

Makroer er ikke fast i s-uttrykk. Se LOOP makro for et svært komplekst språk skrevet med søkeord (symboler). Så, mens du kan starte og avslutte loopen med parentes, inni den har sin egen syntaks.

Eksempel:

(loop for x from 0 below 100
      when (even x)
      collect x)

Når det er sagt, de fleste enkle makroer bare bruke s-uttrykk. Og du vil bli "stuck" med dem.

Men s-uttrykk, som Sergio har svart, begynner å føles riktig. Syntaksen kommer ut av veien og du begynner koding i syntakstreet.

Som for leseren makroer, ja, du kan tenkes å skrive noe sånt som dette:

#R{
      ruby.code.goes.here
  }

Men du trenger å skrive din egen Ruby syntaks parser.

Du kan også etterligne noen av Ruby konstruerer, som blokker, med makroer som kompilere til eksisterende Lisp konstruksjoner.

#B(some lisp (code goes here))

ville oversette til

(lambda () (some lisp (code goes here)))

Se denne siden for hvordan du gjør det.

Svarte 15/09/2008 kl. 15:07
kilden bruker

stemmer
20

Ja, du kan omdefinere syntaksen slik at Lisp blir en kompilator. Du trenger dette ved hjelp av "Reader Makroer", som er forskjellig fra den vanlige "Compiler Makroer" at du sannsynligvis tenker på.

Common Lisp har innebygde anlegget for å definere nye syntaksen for leseren og leser makroer til å behandle denne syntaksen. Denne behandlingen er gjort på skrive tid (som kommer før kompilere eller eval tid). Hvis du vil vite mer om å definere leser makroer i Common Lisp, se Common Lisp Hyperspec - vil du ønsker å lese Ch. 2, "Syntax" og Ch. 23, "Reader" . (Jeg tror ordningen har samme anlegget, men jeg er ikke så kjent med det - se Scheme kilder for Arc programmeringsspråk ).

Som et enkelt eksempel, la oss anta at du vil Lisp å bruke klammeparentes stedet parentes. Dette krever noe sånt som følgende leser definisjoner:

;; { and } become list delimiters, along with ( and ).
(set-syntax-from-char #\{ #\( )
(defun lcurly-brace-reader (stream inchar) ; this was way too easy to do.
  (declare (ignore inchar))
  (read-delimited-list #\} stream t))
(set-macro-character #\{ #'lcurly-brace-reader)

(set-macro-character #\} (get-macro-character #\) ))
(set-syntax-from-char #\} #\) )

;; un-lisp -- make parens meaningless
(set-syntax-from-char #\) #\] ) ; ( and ) become normal braces
(set-syntax-from-char #\( #\[ )

Du forteller Lisp at {er som en (og at} er som a). Deretter oppretter du en funksjon ( lcurly-brace-reader) at leseren vil kalle når den ser en {, og du bruker set-macro-characterfor å tildele denne funksjonen til {. Da fortelle deg Lisp som (og) er som [og] (det er ikke menings syntaks).

Andre ting du kan gjøre er for eksempel, å skape en ny streng syntaks eller bruke [og] for å legge i-fix notasjon og behandle den i S-uttrykk.

Du kan også gå langt utover dette, redefinerte hele syntaks med dine egne makro tegn som vil utløse handlinger i leseren, slik at himmelen virkelig er grensen. Dette er bare en av grunnene til at Paul Graham og andre holder å si at Lisp er et godt språk i å skrive en kompilator.

Svarte 16/09/2008 kl. 19:28
kilden bruker

stemmer
16

Jeg er ikke en Lisp ekspert, pokker jeg er ikke engang en Lisp programmerer, men etter litt eksperimentering med språket jeg kom til den konklusjon at etter en stund parentes begynner å bli 'usynlig' og du begynner å se koden som du vil den skal være. Du begynne å betale mer oppmerksomhet til de syntaktiske konstruksjoner du oppretter via s-exprs og makroer, og mindre til leksikalsk form av teksten i lister og parentes.

Dette er spesielt sant hvis du dra nytte av en god editor som hjelper med innrykk og syntaks farge (prøv å sette parentes til en farge svært lik bakgrunnen).

Du kan ikke være i stand til å erstatte språket helt og få 'Ruby' syntaks, men du trenger ikke det. Takket være det språket fleksibiliteten du kan ende med en dialekt som føles som du følger den 'Ruby stilen til programmering' hvis du vil, uansett hva det ville bety for deg.

Jeg vet at dette er bare en empirisk observasjon, men jeg tror jeg hadde en av de Lisp opplysning øyeblikkene da jeg innså dette.

Svarte 26/08/2008 kl. 09:49
kilden bruker

stemmer
15

Igjen og igjen, nykommere til Lisp ønsker å "bli kvitt all parentes." Det varer i noen uker. Ingen prosjekt for å bygge en alvorlig generell programmering syntaks på toppen av den vanlige S-uttrykk parser noen gang blir noe, fordi programmerere alltid ender opp foretrakk det du nå oppfatter som "parentes helvete." Det tar litt tid å bli vant til, men ikke mye! Når du blir vant til det, og du kan virkelig sette pris på plastisitet av standard syntaks, som går tilbake til språk der det er bare én måte å uttrykke noe bestemt programmering konstruere er egentlig rist.

Når det er sagt, er Lisp et utmerket substrat for å bygge domenespesifikt språk. Like god som, om ikke bedre enn, XML.

Lykke til!

Svarte 16/09/2008 kl. 19:29
kilden bruker

stemmer
12

Den beste forklaringen på Lisp makroer jeg noensinne har sett er på

https://www.youtube.com/watch?v=4NO83wZVT0A

starter på ca 55 minutter i. Dette er en video av en tale av Peter Seibel, forfatter av "Practical Common Lisp", som er den beste Lisp lærebok er det.

Motivasjonen for Lisp makroer er vanligvis vanskelig å forklare, fordi de virkelig kommer til sin rett i situasjoner som er for lang til å presentere på en enkel tutorial. Peter kommer opp med et godt eksempel; du kan forstå det helt, og det gjør godt, riktig bruk av Lisp makroer.

Du spurte: "kan du endre den funksjonelle natur LISP til en mer objektorientert syntaks og semantikk". Svaret er ja. Faktisk, Lisp opprinnelig ikke har noen objektorientert programmering i det hele tatt, ikke overraskende siden Lisp har eksistert siden veien før objektorientert programmering! Men når vi først hørte om OOP i 1978, var vi i stand til å legge det til Lisp lett, ved blant annet makroer. Omsider Common Lisp Object System (CLOS) ble utviklet, en svært kraftig objektorientert programmering system som passer elegant inn Lisp. Det hele kan lastes som en forlengelse - ingenting er innebygd! Det er alt gjort med makroer.

Lisp har en helt annen funksjon, kalt "leser makroer", som kan brukes til å utvide overflaten syntaks av språket. Ved hjelp av leseren makroer, kan du gjøre sublanguages ​​som har C-lignende eller Ruby-lignende syntaks. De forvandle tekst til Lisp, internt. Disse er ikke brukt mye av de fleste reelle Lisp programmerere, hovedsakelig fordi det er vanskelig å forlenge interaktiv utviklingsmiljø for å forstå den nye syntaksen. For eksempel vil Emacs innrykk kommandoer bli forvirret av en ny syntaks. Hvis du er energisk, skjønt, er Emacs utvidbar også, og du kan lære det om den nye leksikalsk syntaks.

Svarte 05/10/2008 kl. 15:03
kilden bruker

stemmer
11

Vanlige makroer operere på lister over gjenstander. Mest vanlig er disse objektene er andre lister (og derved danne trær) og symboler, men de kan være andre gjenstander, slik som strenger, hashtables, brukerdefinert gjenstander, etc. Disse strukturene er kalt S-EXPS .

Så, når du laster inn et kildefilen, vil Lisp kompilatoren analysere teksten og produsere s-EXPS. Makroer operere på disse. Dette fungerer bra, og det er en fantastisk måte å utvide språket i ånden av s-EXPS.

I tillegg kan de nevnte parsing prosessen forlenges gjennom "leser makroer" som lar deg tilpasse måten kompilatoren blir teksten i s-EXPS. Jeg foreslår imidlertid at du omfavne Lisp er syntaks i stedet for å bøye den til noe annet.

Du høres litt forvirret når du nevner Lisp er "funksjonelle natur" og Rubys "objektorientert syntaks". Jeg er ikke sikker på hva "objektorientert syntaks" er ment å være, men Lisp er en multi-paradigmet språk og den støtter objektorientert programmering extremelly godt.

BTW, når jeg sier Lisp, mener jeg Common Lisp .

Jeg foreslår at du setter dine fordommer bort og gi Lisp en ærlig farten .

Svarte 26/08/2008 kl. 09:36
kilden bruker

stemmer
9

Det du spør er litt som å spørre hvordan å bli en ekspert chocolatier, slik at du kan fjerne alt som djevelsk brune ting fra din favoritt sjokoladekake.

Svarte 17/09/2008 kl. 12:14
kilden bruker

stemmer
9

Parentes helvete? Jeg ser ikke mer parentes i:

(function toto)

enn i:

function(toto);

Og i

(if tata (toto)
  (titi)
  (tutu))

ikke mer enn:

if (tata)
  toto();
else
{
  titi();
  tutu();
}

Jeg ser mindre braketter og ';' selv om.

Svarte 16/09/2008 kl. 16:23
kilden bruker

stemmer
6

Ja, du kan fundamentalt endre syntaksen, og selv flykte "parentes helvete". For det må du definere en ny leser syntaks. Se inn leser makroer.

Jeg mistenker imidlertid at for å nå det nivået av Lisp kompetanse til å programmere slike makroer du må fordype deg i språket i en slik grad at du ikke lenger vil vurdere Parent "helvete". Dvs. av den tiden du vite hvordan du kan unngå dem, vil du har kommet til å akseptere dem som en god ting.

Svarte 15/09/2008 kl. 12:07
kilden bruker

stemmer
2

se dette eksemplet på hvordan leseren makroer kan forlenge Lisp leseren med komplekse oppgaver som XML templating:

http://common-lisp.net/project/cl-quasi-quote/present-class.html

denne brukeren bibliotek sammenstiller de statiske delene av XML til UTF-8-kodet bokstavelig byte matriser under kompileringen som er klar til å bli skrive-sequence'd inn i nettverket strømmen. og de er brukbare i normale Lisp makroer, de er ortogonale ... plassering av komma karakter påvirkninger som deler er konstante og som bør vurderes under kjøring.

mer informasjon tilgjengelig på: http://common-lisp.net/project/cl-quasi-quote/

et annet prosjekt som for Common Lisp syntaks utvidelser: http://common-lisp.net/project/cl-syntax-sugar/

Svarte 17/09/2008 kl. 00:30
kilden bruker

stemmer
2

Hvis du ønsker Lisp å se ut som Ruby bruker Ruby.

Det er mulig å bruke Ruby (og Python) i en svært Lisp aktig måte som er en av de viktigste grunnene til at de har fått aksept så raskt.

Svarte 05/08/2008 kl. 07:40
kilden bruker

stemmer
1

En av bruk av makroer som blåste hodet mitt var kompilere-tiden kontroll av SQL-forespørsler mot DB.

Når du innser at du har full språket på hånden ved kompilering-tiden, åpner det opp interessante nye perspektiver. Hvilket også betyr at du kan skyte deg selv i foten i nye og interessante måter (som rende kompilering ikke reproduserbare, noe som kan veldig lett forvandles til en debugging mareritt).

Svarte 19/09/2008 kl. 10:43
kilden bruker

stemmer
1

Det er et vanskelig spørsmål. Siden Lisp er allerede strukturelt så nær en parsetreet forskjellen mellom et stort antall makroer og implementere din egen mini-språk i en parser generator er ikke helt klart. Men, bortsett fra åpning og lukking paren, du kan veldig lett ende opp med noe som ser ingenting som Lisp.

Svarte 06/08/2008 kl. 12:14
kilden bruker

stemmer
1

@sparkes

Noen ganger LISP er den klart språk valg, nemlig Emacs utvidelser. Jeg er sikker på at jeg kunne bruke Ruby til å utvide Emacs hvis jeg ville, men Emacs er designet for å bli utvidet med LISP, så det synes å være fornuftig å bruke det i den situasjonen.

Svarte 05/08/2008 kl. 07:45
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more