Wat Lisp Anders Maakte
December 2001 (herzien mei 2002)
(Dit artikel kwam tot stand als reactie op enkele vragen op de LL1 mailinglijst. Het is nu opgenomen in Revenge of the Nerds.)
Toen McCarthy Lisp eind jaren '50 ontwierp, was het een radicale afwijking van bestaande talen, waarvan Fortran de belangrijkste was.
Lisp belichaamde negen nieuwe ideeën:
1. Conditionals. Een conditional is een if-then-else constructie. We beschouwen deze nu als vanzelfsprekend. Ze werden door McCarthy uitgevonden tijdens de ontwikkeling van Lisp. (Fortran had destijds alleen een conditional goto, nauw gebaseerd op de branch instructie in de onderliggende hardware.) McCarthy, die deel uitmaakte van het Algol-comité, kreeg conditionals in Algol, vanwaaruit ze zich verspreidden naar de meeste andere talen.
2. Een functietype. In Lisp zijn functies first-class objects – ze zijn een datatype net als integers, strings, etc., en hebben een letterlijke representatie, kunnen in variabelen worden opgeslagen, als argumenten worden doorgegeven, enzovoort.
3. Recursie. Recursie bestond natuurlijk al als wiskundig concept vóór Lisp, maar Lisp was de eerste programmeertaal die het ondersteunde. (Het is aantoonbaar impliciet in het maken van functies tot first-class objects.)
4. Een nieuw concept van variabelen. In Lisp zijn alle variabelen effectief pointers. Waarden zijn wat typen hebben, niet variabelen, en het toewijzen of binden van variabelen betekent het kopiëren van pointers, niet van waar ze naar verwijzen.
5. Garbage-collection.
6. Programma's samengesteld uit expressies. Lisp-programma's zijn bomen van expressies, die elk een waarde retourneren. (In sommige Lisps kunnen expressies meerdere waarden retourneren.) Dit staat in contrast met Fortran en de meeste opvolgende talen, die onderscheid maken tussen expressies en statements.
Het was natuurlijk om dit onderscheid te hebben in Fortran omdat (niet verrassend in een taal waar het invoerformaat geponste kaarten was) de taal regel-georiënteerd was. Je kon geen statements nesten. En dus, hoewel je expressies nodig had voor wiskunde om te werken, had het geen zin om iets anders een waarde te laten retourneren, omdat er niemand op zat te wachten.
Deze beperking verdween met de komst van blok-gestructureerde talen, maar toen was het te laat. Het onderscheid tussen expressies en statements was verankerd. Het verspreidde zich van Fortran naar Algol en vandaar naar beide hun nakomelingen.
Wanneer een taal volledig uit expressies bestaat, kun je expressies samenstellen zoals je wilt. Je kunt zeggen (met Arc syntax)
(if foo (= x 1) (= x 2))
of
(= x (if foo 1 2))
7. Een symbooltype. Symbolen verschillen van strings doordat je gelijkheid kunt testen door een pointer te vergelijken.
8. Een notatie voor code met behulp van bomen van symbolen.
9. De hele taal altijd beschikbaar. Er is geen echt onderscheid tussen read-time, compile-time en runtime. Je kunt code compileren of uitvoeren tijdens het lezen, code lezen of uitvoeren tijdens het compileren, en code lezen of compileren tijdens runtime.
Het uitvoeren van code tijdens read-time stelt gebruikers in staat om de syntax van Lisp te herprogrammeren; het uitvoeren van code tijdens compile-time is de basis van macros; het compileren tijdens runtime is de basis van het gebruik van Lisp als extensietaal in programma's zoals Emacs; en het lezen tijdens runtime maakt het mogelijk voor programma's om te communiceren met behulp van s-expressions, een idee dat onlangs opnieuw is uitgevonden als XML.
Toen Lisp voor het eerst werd uitgevonden, waren al deze ideeën ver verwijderd van de gebruikelijke programmeerpraktijk, die grotendeels werd bepaald door de hardware die eind jaren '50 beschikbaar was.
Na verloop van tijd is de standaardtaal, belichaamd in een opeenvolging van populaire talen, geleidelijk geëvolueerd naar Lisp. 1-5 zijn nu wijdverbreid. 6 begint mainstream te worden. Python heeft een vorm van 7, hoewel er geen syntax voor lijkt te zijn. 8, wat (samen met 9) de Lisp macros mogelijk maakt, is tot nu toe nog steeds uniek voor Lisp, misschien omdat (a) het die haakjes vereist, of iets net zo ergs, en (b) als je dat laatste beetje kracht toevoegt, kun je niet langer beweren een nieuwe taal te hebben uitgevonden, maar alleen een nieuw dialect van Lisp te hebben ontworpen ;-)
Hoewel nuttig voor hedendaagse programmeurs, is het vreemd om Lisp te beschrijven in termen van de afwijking van de willekeurige noodoplossingen die andere talen hebben aangenomen. Dat was waarschijnlijk niet hoe McCarthy erover dacht. Lisp was niet ontworpen om de fouten in Fortran te herstellen; het kwam meer voort als een bijproduct van een poging om berekeningen te axiomatiseren.