LISP 860409 (c) 1986 by ORD-GROUP 40 LISP Inleiding LISP was een van de eerste programmeertalen die ontworpen werden. De taal is door McCarthy in 1964 ontworpen als tegenhanger van het toen nieuwe FORTRAN. LISP heeft twee typische eigenschappen, namelijk 'functioneel programmeren' en het feit dat programma's dezelfde vorm hebben als hun data. Functioneel programmeren is een stijl van programmeren waarbij uitsluitend functies worden gebruikt. Een programma bestaat dan uit een aantal functiedefinities, en het enige wat een programma 'doet' is iets uitrekenen. Een programma dat de faculteit uitre- kent ziet er bijvoorbeeld zo uit (in een fantasietaal): fac(n)= IF n=0 THEN 1 ELSE n*fac(n-1) Dit is een definitie van een functie. Waar in een imperatieve (lees: gewone) programmeertaal een lus wordt gebruikt, treedt hier recursie op. Dat is een van de basisprincipes van functio- neel programmeren. Over het algemeen is een functioneel programma korter en leesbaarder dan het imperatieve equivalent. In LISP is dit effect iets minder sterk vanwege de syntax. In LISP ziet het bovenstaande programma er bijvoorbeeld zo uit: (EXPR FAC (LAMBDA (N) (COND ((EQUAL N 0) 1) (T (TIMES N (FAC (PLUS N -1)))) ))) Opvallend is het aantal haakjes. Dat is dan ook een van de meest genoemde nadelen van LISP. Het is ook mogelijk in LISP op een BASIC-achtige manier met assignments en sprongen te programmeren door middel van een speciale functie PROG. Tegenwoordig wordt dat minder gebruikt. De interpreter De interpreter is erop gebouwd om op een relatief kleine computer (zoals de ORDINATOR er een is) te werken. De meeste LISP inter- preters werken op veel grotere computers, die veel sneller zijn en meer geheugen tot hun beschikking hebben. Deze interpreter kan programma's tot zo'n tien pagina's LISP code gemakkelijk verwerken. Dit is bereikt door vele functies in machinetaal te coderen, en door zorvuldig met het weinige geheu- gen om te springen. De LISP interpreter is globaal op te delen in de volgende delen: - Het hoofdprogramma. Dit bevat de cyclus invoer-uitrekenen- uitvoer, een routine om foutmeldingen af te drukken en initialisatieroutines voor het opstarten en het terugkomen na een foutmelding. - De evaluator. Dit is een stelsel van routines die het feitelijke rekenwerk verzorgen. De evaluator gebruikt de LISP 860409 (c) 1986 by ORD-GROUP 41 informatie die bij de atomen is opgeslagen om de bereke- ningen uit te voeren. De evaluator is ook als functie voor de gebruiker beschikbaar (dat is EVAL). - De I/O functies. Dit is de verzameling van alle routines die de I/O verzorgen. Hierin zitten routines die de toet- senbord, beeldscherm, printer en disk verzorgen, en routi- nes die de conversie van S-expressies van en naar de interne representatie hiervan doen. - De interne functies. Deze doen al het interne werk zoals garbage collection en het manipuleren van lijsten. - Het datageheugen. Dit is een stuk geheugen dat wordt gebruikt om alle S-expressies op te slaan. Hier staan alle definities van functies en constantes, tussenuitkomsten van berekeningen en dergelijke zaken in. De evaluator is een A-list evaluator. Dat houdt in dat de functieparameters worden bijgehouden in de vorm van een lijst, genaamd de A-list. Deze lijst bestaat bij de meeste interpreters uit paren (atoom.binding) die de waarde van een atoom in een bepaalde omgeving aangeven. Dat komt in deze interpreter ook voor, maar het binden van meer dan twee variabelen wordt tegelijk gedaan door (atomenlijst.bindingenlijst) op de A-list te zetten. Dit geeft een kleine ruimtebesparing. Een atoom wordt opgeslagen als een paar (binding.naam) met een flag die aangeeft dat het een atoom is. De naam van het atoom is een structuur die van buitenaf niet bekeken kan worden, en de binding is een paar (type.waarde), dat bekeken kan worden door de CAR van het atoom te nemen. De type's zijn APVAL, EXPR, FEXPR, SUBR en FSUBR. De waarde die bij een van de eerste drie typen hoort is een LISP expressie, en de waarde bij de SUBR en FSUBR is een pointer naar een subroutine in machinecode (dus niet afdruk- baar). Met de functie DEF kan onderzocht worden wat voor type (de binding van) een atoom is. Mogelijkheden Globaal overzicht van de mogelijkheden: - Rekencapaciteit: getallen van -16777215 tot +16777215. - Lengte van namen: onbeperkt. Dit hebben wij gedaan omdat iedere bovengrens in principe te laag is. Als wij het over zou doen, zouden we de getallen ook onbegrensd maken. - Er kan een printer worden aangestuurd. Om de zo voor LISP kenmerkende onleesbaarheid wat te verzachten, is er een verfraaiingsfunctie ingebouwd die voor de printer gebruikt kan worden. - Het is mogelijk expressies op disk te zetten en er weer af te halen. Hierdoor is het mogelijk programma's op een comfortabele manier met een tekstverwerker te schrijven. - Er zijn vele (ongeveer 100) standaardfuncties ingebouwd, waarvan ongeveer de helft in machinecode is gecodeerd. Dit vergroot de snelheid van de meeste programma's tot een relatief hoog niveau. - Er zijn tegenwoordig steeds meer mensen die alleen met functioneel LISP willen werken. Dat is mogelijk bij deze interpreter. Ook de niet-functionele kant van LISP is LISP 860409 (c) 1986 by ORD-GROUP 42 ingebouwd, omdat er mensen zijn die dat gebruiken willen, en omdat men er de snelheid van een berekening mee kan verhogen. De mensen die dit niet willen gebruiken hoeven dat niet te doen. - De PROG functie is ingebouwd. Dit is handig om bepaalde dingen, zoals input/output, makkelijker te organiseren. Ook kan het gebruikt worden om snelheid en geheugen te besparen. - Het is tamelijk eenvoudig er zelf functies in machinetaal aan toe te voegen. Conclusie LISP op een 8 bits microcomputer is best mogelijk. Het gaat niet al te snel maar er kunnen hele leuke dingen mee gedaan worden.