LISP - vad är det ? av Anders Ström LISP är ett av de äldsta programmeringspråk som ännu är i bruk, det började användas 1960. Trots sin relativt höga ålder innehåller språket mycket som fortfarande inte finns i nyare språk. Denna artikel är ett försök att beskriva vissa grundläggande ideer, som ligger bakom LISP. Vi börjar med ett exempel. Om man skriver in följande till en LISP interpretator (TIMES PI (PLUS 12 4 -11)) skulle den villigt lämna svaret 15.70 under förutsättning att PI har värdet 3.14. Redan detta enkla exempel visar mycket som är typiskt för LISP. Man skriver in ett uttryck som omedelbart beräknas (evalueras), varefter resultatet skrivs ut. Ett program i LISP lagras direkt i LISPs grundläggande datastrukturer, nämligen atomer och listor. Denna ekvivalens mellan program och data, gör LISP utmärkt för att operera på LISP program. Man kan på ett par sidor definiera en LISP interpretator i LISP. En atom är entydigt definerad av sitt namn. Dvs om två atomer skrivs ut på samma sätt är det samma atom. Exempel på atomer är PI, PLUS, 2 och 1-FOO. Atomerna delas in i två grupper, numeriska atomer och literala atomer. Till varje literal atom kan vi associera ett godtyckligt antal egenskaper. Två av dessa egenskaper är speciella, så man bör minnas dem, nämligen atomens värde och dess funktions-definition . En lista börjar med en vänsterparantes och innehåller sen ett godtyckligt antal element, som vart och ett kan vara en lista eller en atom, och avslutas med en högerparantes. När ett uttryck skall evalueras tittar interpretatorn först på om det är en atom eller lista som ska evalueras. Om det är en atom returneras värdet av atomen. Om det är en lista tolkas första elementet i listan, som vi förutsätter är en atom med funktions egenskap, som namnet på en funktion, och resten av listan som argumenten till denna funktion. På detta sätt kan vi ge godtyckligt många argument till en funktion, t.ex. PLUS kan ta hur många argument som helst. Nästa steg i evalueringen blir nu att evaluera argumenten till funktionen. Dessa evalueras på samma sätt, dvs interpretatorn anropar sig själv. Till sist applicerar vi funktionen till de aktuella argumenten. <1> Ovan gjorde vi en enkel numerisk beräkning, men LISP är inte bara till för att göra numeriska beräkningar, utan framför allt till för att hantera symboler. Vi kan till exempel hålla ordning på vilka som är våra vänner genom att skriva (SETQ VÄNNER '(LISA PELLE DATORN)) Funktionen SETQ sätter den variabel som är första argument till värdet av andra argumentet. Vad gör nu blippen (') i uttrycket? Vi vill ju att VÄNNER skall få värdet (LISA PELLE DATORN), och inte det som lämnas tillbaka om vi beräknar uttrycket (LISA är en odefinierad funktion). Blippen (eller "quote" som varje garvad LISP programmerare säger) betyder helt enkelt att vi inte ska beräkna utrycket för att få värdet, utan att vi ska ta uttrycket i sig självt som värde. <2> Om vi senare vill ha reda på vilka som är våra vänner skriver vi VÄNNER varvid svaret blir (LISA PELLE DATORN) Följande två exempel belyser skillnaden mellan att använda quote och inte. Först med quote (SETQ KOMPISAR 'VÄNNER) VÄNNER Här sätts KOMPISAR till VÄNNER. Och utan quote (SETQ KOMPISAR VÄNNER) (LISA PELLE DATORN) Här sätter vi alltså KOMPISAR till (LISA PELLE DATORN), dvs värdet av VÄNNER. Vi kan också hålla reda på våra fiender, vi skriver (SETQ FIENDER '(OLLE TROLLET SPÖKET)) Om vi vi en dag upptäcker att TROLLET är vår vän och inte en fiende, så måste vi kunna ändra på det. Vi skriver då (SETQ VÄNNER (CONS 'TROLLET VÄNNER)) (TROLLET LISA PELLE DATORN) samt (SETQ FIENDER (REMOVE 'TROLLET FIENDER)) (OLLE SPÖKET) CONS adderar det element som ges som första argument till listan som ges som andra argument. REMOVE plockar bort alla förekomster av argumentet i listan som ges som andra argument. Om vi har många vänner och många fiender, och vi hela tiden ändrar oss vad gäller vem som tillhör vilken grupp, så blir det ganska jobbigt att skriva in allt detta varje gång kan då definiera en funktion för att förenkla det. (DE GÖR_TILL_VÄN (NAMN) (SETQ VÄNNER (CONS NAMN VÄNNER) (SETQ FIENDER (REMOVE NAMN FIENDER))) Då kan vi i stället skriva (GÖR_TILL_VÄN 'TROLLET) Funktionen DE som används för att definera andra funktioner kan besrivas med (DE ... ) Där ord inom vinkelparanteser anger vad som ska placeras i deras ställe. Värdet av en funktion är samma som värdet av den sista elementet, dvs , i listan som utgör funktionen. Naturligtvis har även funktionen DE ett värde, nämligen namnet på den funktion man just har definerat. Den uppmärksamme läsaren har naturligtvis redan ställt sig frågan: "Skulle man inte evaluera argumenten till en funktion, hur går det ihop med anropet till DE ovan?" Helt rätt, vi har inte berättat allt ännu. Genom att använda funktionen DF istället för DE när vi definerar en funktion, kan vi få en speciell typ av funktioner (så kallade FEXPRs till skillnad från EXPRs) som inte ska ha sina argument evaluerade. DE och DF är exempel på FEXPRs. Vi ska inte här gå djupare in på LISP, men för den som vill läsa mer om LISP rekomenderas Patrick Winstons bok "Artificial Intelligence" (Exemplet med vänner och fiender är stulet från denna bok.) Boken beskriver ett problemområde där man ofta använder LISP som ett redskap, nämligen artificiell intelligens, samt hur man använder LISP där och anorstädes. --------------------------------------------------------------------- <1> Det vållar ofta nybörjaren problem att hålla reda på när man ska använda quote och inte. Detta är särskilt markant om personen i fråga har använt andra programmerings språk tidigare. Det beror på att man där ofta fuskar bort problemet genom att helt enkelt bara tillåta den ena varianten. Om vi tittar på PASCAL och utgår från deklarationen type färg = (röd, grön, blå); sedan kan man inte använda röd som en variabel, för hur ska man kunna veta vad x:=röd betyder. Menar man variabeln röd eller röd som ingående i typen färg. <2> I LISP nöjer vi oss med funktioner medan man i andra språk använder använder sig av fuktioner, procedurer och operatorer. En funktion lämnar alltid ett värde, även om det många gånger slängs bort omeddelbart.