Göm menyn

Allegro Common Lisp FAQ

Här finns lösningar på problem som kan dyka upp när man kör Allegro Common Lisp via Emacs.

1. Grundläggande Emacs

1.1. Hur fungerar Emacs-kommandon?
1.2. Vad innehåller filen .emacs?
1.3. Hur stänger jag en buffert eller ett delfönster?

2. Problem vid inmatning av programkod

2.1. Hur får jag Emacs att färglägga min Lisp-kod?
2.2. Hur ändrar jag färgerna i Emacs?
2.3. Varför blir indenteringen fel på första raden i filen?
2.4. Kan man indentera om större delar av programkoden?
2.5. Kan man kommentera bort en funktion på ett enkelt sätt?

3. Problem vid evaluering

3.1. Varför vägrar Allegro att evaluera min fil?
3.2. Vad betyder "ignoring extra right parenthesis"?
3.3. Vad betyder ":OPERATOR was defined in..."?
3.4. Vad betyder "eof encountered on stream..."?

4. Problem vid körning

4.1. Varför skrivs inte hela listan ut?
4.2. Vad innebär listan "Restart actions" och varför står det "[1]" framför Lisp-prompten?
4.3. Vad betyder "`X' is not of the exptected type `Y'"?
4.4. Vad betyder "Attempt to call `X' which is an undefined function"?
4.5. Varför står det \201 mitt i funktionsnamnet?
4.6. Vad betyder "Attempt to take the value of the unbound variable `X'"?
4.7. Vad betyder "Illegal function object"?
4.8. Vad betyder "Attempt to take the cdr of X which is not listp"?

5. Felsökning

5.1. Hur kommer man tillrätta med parentesfel?


1. Grundläggande Emacs

Detta avsnitt upptar några grundläggande punkter angående Emacs som är viktiga för att förstå resten av dokumentet. För mer information om Emacs hänvisas till det introduktionsmaterial som finns i STONE.

1.1. Hur fungerar Emacs-kommandon?

I denna FAQ, liksom i all dokumentation för Emacs, används ett standardiserat sätt att uttrycka kommandon som man matar in till Emacs. Följande exempel illusterar vad kommandona betyder.

C-x C-s Håll ner Control-tangenten och tryck samtidigt på X. Släpp därefter alla tangenter. Håll sedan ner Control-tangenten och tryck samtidigt på S. (Detta kommando sparar den aktuella bufferten i en fil.)
C-x k Håll ner Control-tangenten och tryck samtidigt på X. Släpp därefter alla tangenter och tryck sedan på enbart K. (Detta kommando stänger en buffert. Om du trycker på Enter vid frågan stängs den aktuella bufferten.)
M-x common-lisp-mode Håll ner Meta-tangenten (markerad med en diamant) och tryck samtidigt på X. Släpp därefter alla tangenter. Skriv in common-lisp-mode i minibufferten och tryck på Enter. (Kommandot tvingar en buffert till Common Lisp-läge.)

1.2. Vad innehåller filen .emacs?

Varje gång Emacs startas letar programmet efter en fil med namnet .emacs i din hemkatalog. I denna fil placeras dina personliga inställningar och anpassningar av Emacs. Filen .emacs är en vanlig textfil som med fördel kan editeras i Emacs självt. Alla inställningar formuleras som Lisp-kod, eftersom Emacs har en särskild dialekt av Lisp inbyggd i sig. Följande är ett exempel på inställningar som .emacs kan innehålla:

(column-number-mode t) (show-paren-mode t)

Den första raden slår på visning av aktuell kolumn. Det innebär att numret på den kolumn där markören befinner sig visas i statusraden. Den andra raden slår på visning av parenteser. Det innebär att om markören placeras på en startparentes eller direkt efter en slutparentes så kommer denna och den matchande parentesen att visas med en särskild färg. Detta underlättar t.ex. vid felsökning av Lisp-kod.

1.3. Hur stänger jag en buffert eller ett delfönster?

Vid vissa typer av fel i Allegro öppnas en ny buffert, typiskt med namnet *background-interaction*. För att stänga denna buffert används kommandot C-x k. När du kör kommandot visas en fråga i minibufferten om vilken buffert du vill stänga. Tryck Enter för att stänga den aktuella bufferten.

Om felet har öppnat ett nytt delfönster räcker det inte med att stänga bufferten. Man måste också stänga delfönstret. För att göra detta används kommandot C-x 0. Observera att kommandot stänger det delfönster som för närvarande är aktivt.


2. Problem vid inmatning av programkod

Detta avsnitt upptar problem som uppstår när man skriver programkod i den övre bufferten i Allegro, dvs den buffert som normalt är i läget (Common Lisp; pkg:user).

2.1. Hur får jag Emacs att färglägga min Lisp-kod?

De normala inställningarna är att Emacs färglägger Lisp-kod så att t.ex. funktionsnamnet i en definition visas i blått och kommentarer i rött. Om din Lisp-kod inte blir färglagd bör du först kontrollera att bufferten är i Common Lisp-läge. I statusraden längst ner bör det stå (Common Lisp; pkg:user). Om du öppnar en fil med ändelsen .cl hamnar bufferten automatiskt i Common Lisp-läge, men du kan också tvinga fram det med kommandot M-x common-lisp-mode.

Om din Lisp-kod fortfarande inte är färglagd efter dessa åtgärder behöver du slå på färgningsläget. Detta gör du med kommandot M-x font-lock-mode. För att slippa göra detta för varje fil du öppnar kan du istället lägga in följande rader i .emacs

(global-font-lock-mode t) (setq font-lock-maximum-decoration t)

Du kan också aktivera eller stänga av färgning via menyerna i Emacs. I version 20 använder du alternativet Global Font Lock i undermenyn Option i menyn Help. I version 21 använder du alternativet Syntax highligting i menyn Options.

2.2. Hur ändrar jag färgerna i Emacs?

Du kan ändra grundfärgerna i Emacs genom att lägga till följande rader i .emacs

(set-background-color "White") (set-foreground-color "Black") (set-cursor-color "Black")

Du kan ändra de färger som används för att färglägga programkod genom att lägga till följande rader i .emacs

(setq font-lock-face-attributes '((font-lock-comment-face "FireBrick" nil nil t nil) (font-lock-function-name-face "Blue" nil t nil nil) (font-lock-keyword-face "Black" nil t nil nil) (font-lock-string-face "ForestGreen" nil nil t nil) (font-lock-type-face "Blue" nil nil nil nil) (font-lock-variable-name-face "Black" nil nil nil nil) (font-lock-reference-face "ForestGreen" nil nil nil nil)))

De fyra parametrarna som är nil eller t i ovanstående har från vänster till höger följande betydelse: bakgrundsfärg (eller nil om standardbakgrund ska användas), om koden ska visas i fetstil, om koden ska visas i kursiv stil samt om koden ska visas understruken.

För att se en lista med alla tillgängliga färger och deras namn, använd kommandot M-x list-colors-display.

2.3. Varför blir indenteringen fel på första raden i filen?

I sällsynta fall kan det inträffa att man börjar skriva in en definition först i en fil och trycker på Enter varvid Emacs indenterar raden fyra steg och tappar färgningen. Detta beror på ett fel i Common Lisp-läget i Emacs och det uppträder när du har skrivit in en halvfärdig definition, ångrat dig och tagit bort den och sedan börjat skriva in en ny definition.

För att lösa problemet ska du komplettera med högerparentser så att den nuvarande, felaktigt indenterade, definitionen blir färdig. Tryck därefter på Enter. Ta sedan bort definitionen och börja om.

2.4. Kan man indentera om större delar av programkoden?

Man kan alltid trycka på Tab för att indentera den aktuella raden, oavsett var markören står. Att trycka omväxlande på Tab och nedåtpil är oftast det enklaste sättet att indentera om kortare delar av kod.

För att indentera om en hel funktion kan man ställa sig i början av definitionen och trycka C-M-q. Man kan också sätta ett märke med C-Space, placera markören på ett annat ställe och indentera om hela det nu markerade området med kommandot M-x indent-region.

2.5. Kan man kommentera bort en funktion på ett enkelt sätt?

Du kan kommentera bort ett stycke kod genom att först sätta ett märke med C-Space, därefter flytta markören till ett annat ställe och till sist använda kommandot C-c ;. Då kommer alla rader mellan märket och markörens nuvarande position att förses med semikolon i början.

Du kan också använda alternativet Comment Form i menyn ACLEdit för att kommentera den funktionsdefinition som markören för närvarande står i. I samma meny finns också alternativen Uncomment Region och Uncomment form som har motsatt effekt.


3. Problem vid evaluering

Detta avsnitt upptar problem som uppstår när man försöker evaluera programkod i den övre bufferten i Allegro, dvs den buffert som normalt är i läget (Common Lisp; pkg:user).

3.1. Varför vägrar Allegro att evaluera min fil?

I normala fall ska resultatet av evalueringen bli att resultatet av det sista uttrycket visas i minibufferten, oftast namnet på den sist definierade funktionen. Om Emacs piper och inte ser ut att ha evaluerat något kan det bero på två saker.

Den första möjliga orsaken är att den buffert du står i inte är i Common Lisp-läge. Evalueringskommandona, t.ex. C-c C-b, finns endast tillgängliga i detta läge. Statusraden i den aktuella bufferten ska innehålla (Common Lisp; pkg:user). Du kan försätta bufferten i rätt läge antingen genom att spara filen med ett namn som slutar på .cl eller genom kommandot M-x common-list-mode.

Den andra möjliga orsaken är att du har råkat avsluta Allegro-processen. Ta en titt i menyn ACLfile. Om menyvalet Run/Restart Common Lisp är valbart (dvs inte skuggat) så betyder det att din Allegro-process inte är igång. Åtgärda detta genom att välja sagda menyval.

3.2. Vad betyder "ignoring extra right parenthesis"?

Denna varning dyker upp i en ny buffert och brukar se ut så här:

Warning: ignoring extra right parenthesis

Detta betyder att det finns för många högerparenteser i din kod. Funktionerna kommer antagligen att fungera, men det kan vara bra att lokalisera och åtgärda felet ändå.

För information om hur man stänger bufferten, se svar på fråga 1.3.

3.3. Vad betyder ":OPERATOR was defined in..."?

Denna varning dyker upp i en ny buffert och kan t.ex. se ut så här:

Warning: FAKULTET, :OPERATOR was defined in /home/petda123/rename-me.cl and is
         now being defined in /home/petda123/fakultet.cl

Det här felet uppstår när du har definierat samma funktion i två olika filer. Det är bara en varning, så antaligen kommer funktionerna att fungera, men du bör fundera över om du kan stänga en eller flera filer samt i vilken ordning du egentligen vill evaluera dina olika filer.

För information om hur man stänger bufferten, se svar på fråga 1.3.

3.4. Vad betyder "eof encountered on stream..."?

Detta något kryptiska felmeddelande brukar visas i en ny buffert och kan t.ex. se ut så här:

Error: eof encountered on stream #<EXCL::STRING-INPUT-STREAM @ #x84ddb8a>
  [condition type: END-OF-FILE]
[Current process: Evaluation Request 3]
[1] USER(1): 

Felet uppstår när det finns för få högerparenteser i din kod. Det kommer sig av att Allegro hittar slutet på filen (eof=end of file) innan den har hunnit bli färdig med evalueringen.

För information om hur man stänger bufferten, se svar på fråga 1.3.


4. Problem vid körning

Detta avsnitt upptar problem som uppstår när man försöker evaluera uttryck i den undre bufferten i Allegro, dvs den buffert som heter *common-lisp* och är i läget (Inferior Common Lisp).

4.1. Varför skrivs inte hela listan ut?

I Lisp kan du normalt inte skriva ut hur långa listor som helst. Detta är ett sätt att slippa att jättelånga listor eller cirkulära strukturer plötsligt skrivs ut. Det finns två gränsvärden: ett som talar om hur långa listor som kan skrivas ut och ett som talar om hur djupt en lista skrivs ut, dvs hur många nivåer ner. Om en lista är för lång kommer bara de första elementen att skrivas ut medan resten ersätts med ... och på samma sätt kommer djupare nivåer att ersättas med #. För att utöka gränsen när du vill felsöka eller av någon annan anledning vill skriva ut långa listor kan du göra så här:

CL-USER(1): (make-list 25)
(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL ...)
USER(2): (setq top-level:*print-length* 100)
100
CL-USER(3): (make-list 25)
(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL
 NIL NIL NIL NIL NIL NIL)
CL-USER(4): '(a (b (c (d (e (f (g)))))))
(A (B (C (D (E #)))))
CL-USER(5): (setq top-level:*print-level* 100)
100
CL-USER(6): '(a (b (c (d (e (f (g)))))))
(A (B (C (D (E (F (G)))))))

4.2. Vad innebär listan "Restart actions" och varför står det "[1]" framför Lisp-prompten?

Så fort ett fel inträffar under evalueringen av ett Lisp-uttryck hamnar Allegro i felsökningsläge. Man känner igen detta genom att Lisp-promten inleds med ett tal inom hakparenteser. Det första som är intressant att titta på är dock felmeddelandet som står på den första raden omedelbart efter det uttryck som du skrev in. De följande frågorna i detta avsnitt tar upp olika sådana felmeddelanden.

När du är i felsökningsläget kan du välja mellan olika åtgärder för att fortsätta körningen. Oftast är man dock inte intresserad av detta, utan vill lokalisera och korrigera felet i programkoden. För att hoppa ur felsökningsläget använder du kommandot :reset som skrivs in utan parenteser direkt vid Lisp-prompten. Det går också bra att förkorta det till :res.

Tips angående felsökning finns i nästa avsnitt av denna FAQ.

4.3. Vad betyder "`X' is not of the exptected type `Y'"?

Detta fel innebär att en funktion har anropats med minst ett argument som var av fel typ. Felet kan t.ex. uppstå genom uttrycket (+ '(1 2) '(3 4)) eftersom funktionen + inte kan operera på listor.

För att lokalisera var någonstans i programkoden som felet uppstod, använd :zoom (se fråga 5.?).

4.4. Vad betyder "Attempt to call `X' which is an undefined function"?

Detta fel beror oftast på att du har stavat fel till ett funktionsnamn. Ibland kan det också bero på parentesfel, eftersom allt som står först i en lista betraktas som ett funktionsnamn.

4.5. Varför står det \201 mitt i funktionsnamnet?

Om du får felet "Attempt to call `X' which is an undefined function" och felmeddelandet refererar till ett funktionsnamn som innehållet \201 eller liknande konstigheter så beror det på att filen är sparad med fel teckenuppsättning. Felet uppträder inte när du tittar på filen i ett skalfönster eller när du öppnar den och evaluerar den via Emacs, utan endast när du laddar in den med load. Antagligen har du arbetat med filen hemifrån och lyckats spara den i en teckenuppsättning som gör att load inte klarar av att ladda in funktioner som har svenska tecken i namnet. För att lösa problemet, gör följande (inloggad lokalt i datasalarna på IDA):

  1. Öppna filen i Emacs.
  2. Kör kommandot C-x RET f (där RET betyder Enter).
  3. Tryck Enter för att acceptera det förvalda värdet.
  4. Spara filen.
  5. Tryck Enter för att acceptera det förvalda värdet.

Filen är nu sparad med en teckenuppsättning som gör att den går att ladda in även med load.

4.6. Vad betyder "Attempt to take the value of the unbound variable `X'"?

Detta fel beror oftast på att du har stavat fel till ett variabelnamn.

4.7. Vad betyder "Illegal function object"?

Den generella regeln är att varje gång Lisp-evaluatorn ser en vänsterparentes så förväntar den sig att det som kommer efteråt är namnet på en funktion (eller möjligen ett uttryck som kan bli en funktion, t.ex. ett lambda-uttryck). Om så inte är fallet signaleras ovanstående fel.

Felet beror oftast på att parenteser hamnat fel, typiskt i de fall som utgör undantag från ovanstående regel (t.ex. cond, let).

4.8. Vad betyder "Attempt to take the cdr of X which is not listp"?

Det här felet beror inte nödvändigtvis på att du använt funktionen cdr på ett felaktigt sätt. Det beror oftare på att du försökt använda endp på något som inte är en lista. Funktionen endp förutsätter att argumentet är en lista, tom eller inte, men klarar inte av att hantera symboler. Felet kan provoceras fram t.ex. med uttrycket (endp 'a). Lösningen på problemet är inte att byta ut funktionen endp utan att istället se till att det som skickas in till funktionen alltid är en lista. Felet uppkommer typiskt vid dubbelrekursion när man skickar in fel del av listan i det rekursiva anropet.


5. Felsökning

Detta avsnitt upptar mer allmänna frågor kring felsökning i Allegro Common Lisp.

5.1. Hur kommer man tillrätta med parentesfel?

När du skriver in funktioner i den övre bufferten så markerar Allegro hur parenteserna matchar varandra genom att för varje högerparentes snabbt hoppa till motsvarande vänsterparentes. Ett av de enklaste sätten att kontrollera parenteser är därför att ta bort några stycken och därefter skriva dit dem igen, en i taget.

Ett annat tips kan vara att låta Allegro avsluta funktionerna åt dig. Med alternativet Close all parens i menyn ACLEdit kan du låta Allegro fylla i slutparenteserna om markören står i slutet av en funktion. Du kan också göra detta med tangentkombinationen C-c ].

Genom att klicka med vänster musknapp på den första parentesen i funktionen, dvs den innan defun, markerar du hela funktionen. Detta kan också vara ett sätt att hitta parentesfel, för om det saknas slutparenteser kommer Allegro inte kunna markera funktionen utan piper istället.

Ett mer generellt tips för att undvika parentesfel från första början är att inte skriva så långa rader. Varje gång du trycker Enter indenterar Lisp åt dig. På det sättet syns strukturen i funktionen tydligt och du märker om något är fel. Skriv t.ex. if-satser på tre rader och dela upp raderna i cond-satsen om det behövs.

Se även svar på fråga 2.4 om hur man kan indentera om delar av koden.


Sidansvarig: Peter Dalenius
Senast uppdaterad: 2005-04-18