LlSP - hur fungerar det ? Av Anders Ström Låt oss omedelbart titta på ett exempel. Om du 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. Du 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 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. Till varje atom kan vi associera ett godtyckligt antal egenskaper. Två av dessa egenskaper är så speciella att man bör minnas dem, nämligen atomens värde och dess funktions definition. En lista börjar med en vänsterparantes och 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 uttrycket för att få värdet, utan att vi ska ta uttrycket i sig själv 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) Låt mig nu ge två exempel som klart visar 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å vara 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 vår fiende, så måste vi kunna ändra på det. Vi skriver då (SETQ VÄNNER (CONS 'TROLLET VÄNNER)) (TROLLET LISA PELLE DATORN) (SETQ FIENDER (REMOVE 'TROLLET FIENDER)) (GLLE SPKET) CONS adderar det element som ges som första argument till listan som ges som andra argument. REMOVE plockar bort alla förekomster av första 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. Vi 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 istä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 beskriver vad som ska placeras dess ställe. Värdet av en funktion är samma som värde av den sista formen () i funktionen. Naturligtvis har även funktionen DE ett värde, nämligen den funktion man just har definerat. Nu hoppas jag att alla läsare har undrat "Skulle man inte evaluera argumenten till en funktion, hur går det ihop med anropet till DE ovan?" Helt rätt, jag 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å special funktioner (så kallade FXPRs till skillnad från EXPRs) som inte ska ha sina argument evaluerade. DE och DF är exempel på FEXPRs. Även funktionen SETQ är en FEXPR, den ska ju inte evaluera sitt första argument. Det finns en funktion SET som fungerar som SETQ med den skillnaden att den evaluerar båda sina argument. Vi kan nu definera SETQ med hjälp av SET. (DF SETQ (X Y) (SET X (EVAL Y))) Där EVAL är ett explicit anrop till LISP interpretatorn. Mycket mer finns att säga om LISP, men press-stop avlägsnar sig alltmer, så någon gång måste det ta slut. Men om inte himlen rasar ner över oss är det möjligt att det blir någon mer artikel om LISP i senare nummer av GARB. För den som inte kan hålla sig rekommenderas Patrick Winstons bok "Artificial Intelligence", den lär finnas på biblioteket. (Jag har stulit en del exempel från den boken.) ---------------------------------------------------------------- <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 programmrings 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 funktioner, procedurer och operatorer. En funktion lämnar alltid ett värde, även om det många gånger slängs bort omedelbart.