Common Lisp 似乎不理解脚本中的 cdr 请求,但在 REPL 中理解它

Common Lisp doesn't seem to understand a cdr request in a script but does understand it in the REPL

下午好。

我正在自学 Common Lisp,运行 遇到了我代码中特定行的问题。

这是一个在竞技场中进行战斗的两个房间的冒险 - 整个目标是一次编写提示命令,因此我必须为 Common Lisp 设置一种查看一行文本的方式并确定哪个是房间,哪个是进去的方向。

我决定将其编码为:


(defparameter  *world* '(room  direction))

然后像这样分隔房间和方向:


(defparameter *direction* (cdr *world*))


(defparameter *room* (car  *world*)

common lisp 好像看不懂


(defparameter *direction* (cdr *world*))

并告诉我:


Unhandled SB-C::INPUT-ERROR-IN-LOAD in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                                 {10010B0523}>:
  READ error during LOAD:

    end of file on #<SB-SYS:FD-STREAM for "file C:\Users\micha\common_lisp\arena.lisp" {10022F4C23}>

    (in form starting at line: 169, column: 41, file-position: 4438)

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10010B0523}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SB-C::INPUT-ERROR-IN-LOAD {10024CEF73}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<SB-C::INPUT-ERROR-IN-LOAD {10024CEF73}>)
2: (INVOKE-DEBUGGER #<SB-C::INPUT-ERROR-IN-LOAD {10024CEF73}>)
3: (ERROR #<SB-C::INPUT-ERROR-IN-LOAD {10024CEF73}>)
4: (SB-C:COMPILER-ERROR SB-C::INPUT-ERROR-IN-LOAD :CONDITION #<END-OF-FILE {10024CEF43}> :POSITION 4438 :LINE/COL NIL :STREAM #<SB-SYS:FD-STREAM for "file C:\Users\micha\common_lisp\arena.lisp" {10022F4C23}>)
5: (SB-C::%DO-FORMS-FROM-INFO #<CLOSURE (LAMBDA (SB-KERNEL:FORM &KEY :CURRENT-INDEX &ALLOW-OTHER-KEYS) :IN SB-INT:LOAD-AS-SOURCE) {10022FBE3B}> #<SB-C::SOURCE-INFO {10022FBDF3}> SB-C::INPUT-ERROR-IN-LOAD)
6: (SB-INT:LOAD-AS-SOURCE #<SB-SYS:FD-STREAM for "file C:\Users\micha\common_lisp\arena.lisp" {10022F4C23}> :VERBOSE NIL :PRINT NIL :CONTEXT "loading")
7: ((FLET SB-FASL::THUNK :IN LOAD))
8: (SB-FASL::CALL-WITH-LOAD-BINDINGS #<CLOSURE (FLET SB-FASL::THUNK :IN LOAD) {96F2EB}> #<SB-SYS:FD-STREAM for "file C:\Users\micha\common_lisp\arena.lisp" {10022F4C23}>)
9: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) #<SB-SYS:FD-STREAM for "file C:\Users\micha\common_lisp\arena.lisp" {10022F4C23}> NIL)
10: (LOAD #<SB-SYS:FD-STREAM for "file C:\Users\micha\common_lisp\arena.lisp" {10022F4C23}> :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST T :EXTERNAL-FORMAT :DEFAULT)
11: ((FLET SB-IMPL::LOAD-SCRIPT :IN SB-IMPL::PROCESS-SCRIPT) #<SB-SYS:FD-STREAM for "file C:\Users\micha\common_lisp\arena.lisp" {10022F4C23}>)
12: ((FLET SB-UNIX::BODY :IN SB-IMPL::PROCESS-SCRIPT))
13: ((FLET "WITHOUT-INTERRUPTS-BODY-2" :IN SB-IMPL::PROCESS-SCRIPT))
14: (SB-IMPL::PROCESS-SCRIPT "arena.lisp")
15: (SB-IMPL::TOPLEVEL-INIT)
16: ((FLET SB-UNIX::BODY :IN SAVE-LISP-AND-DIE))
17: ((FLET "WITHOUT-INTERRUPTS-BODY-7" :IN SAVE-LISP-AND-DIE))
18: ((LABELS SB-IMPL::RESTART-LISP :IN SAVE-LISP-AND-DIE))
19: ("foreign function: #x43270B")
20: ("foreign function: #x403F08")

我通过加载脚本在 repl 中尝试了这个,然后在 repl 中输入


*world*

给我预期的结果:

(ROOM DIRECTION)

进入


(car *world*)

给我预期的结果:

ROOM


(cdr *room*)

给我预期的结果:

(DIRECTION)

不太确定为什么会出错,是的,我会展示代码。 我会请你不要直接告诉我答案,只要把我推向正确的方向,拜托

这是代码本身:

;; Area - an arena battle in Common Lisp
;;
;; There will be two directions, north to the arena and south away from it
;; The player won't be allowed to leave the area.
;; The player and the gladiator's stats will be randomly rolled
;; The combat will be randomly rolled as well
;; The prompt will be coded one time only too.
;; The following variables will be used:
;;
;; Player
;; gladiator
;; world  - which will be a combination of  the following two variables:
;;         room
;;         direction
;;
;; NextRoom
;;
;;phealth  (randomly rolled)
;; ghealth (randomly rolled)
;; pstrength (randomly rolled)
;; gstrength (randomly rolled)
;; pdexterity (randomly rolled)
;; gdexterity (randomly rolled)
;; description  - the room description
;; path - the exits available
;; prompt
;;
;;

;; First set up the global variables

;; set a random state for the dice throw

(setf  *random-state* (make-random-state t))

;; This is you , the player

(defun *player* () )

;; This is your computer generated opponent

(defun *gladiator* () )

;; This defines the world as it exists within this program

(defun *world* () )

;; The particular room you're in

(defun *room* () )

;; This is the exits that are available.
;; We have to use a word other than "exit" because it's a reserved word
;; in Common Lisp and would throw an error if we try to define it
;; to something other than what it's set up for.

(defun *direction* () )

;; This is used to tell the computer to move ahead to the next room.
;; We could POTENTIALLY make room = room, but that's really confusing
;; We want to make this code as clear as is possible
;; Camel case isn't an absolute necessity, however when using a two-word
;; definition, it makes it easier to remember.  REMEMBER, to the computer
;; NextRoom isn't the same is nextroom, Nextroom or nextRoom!

(defun *NextRoom* () ) 

;; This is your health

(defun *phealth* ()
)

;; This is your opponent's health

(defun *ghealth* () )

;; This is your strength

(defun *pstrength* () )

;; This is your opponents strength

(defun *gstrength* () )

;; This is your dexterity

(defun *pdexterity* () )

;; This is your opponents dexterity

(defun *gdexterity* () )

;; This is the prompt - where you enter your  all of your commands

(defun *prompt* () )

;; We'll be using dice to set up players stats, the gladiator stats and it will
;; add a bit of randomness to the combat

(defun *dice* ()
(+ 1  (random 200 )))

;; now set up *dice1* for the d20 rolls

(defun *dice1* ()
  (+ 1 (random 20 )))

;; Here we'll roll the stats for our player and our gladiator
;; both will be randomized. We'll be rolling for health
;; strength and dexterity.
;; A d200 will be  used to health
;; A d20 will be used for both strength and dexterity


;; Now setup the dice roll that will be used for combat
(defun *dice_combat* ()
  (+ 1 (random 20)))

;; players health first

(let ( *phealth* *dice*))


;; now we set the gladiator's health

(let ( *ghealth* *dice*))


;; now we roll the players strength

(let ( *pstrength* *dice1*))

;; now we roll the gladiator's strength

(let ( *gstrength* *dice1*))

;; now we set up the player's dexterity

(let ( *pdexterity* *dice1*))

;; now we set up to gladitor's dexterity

(let ( *gdexterity* *dice1*))


;; now we define difference - this will be used to gauge strike effectiveness
;; and damage between the player and the gladiator

(defparameter *difference* () )

#| now we setup the "world" function which consists of
 two sub - functions, room and direction.
 We're going to run them together, for example
 (arena south) is going to be our way of stating that
 an arena is south of us.  We'll be using cadr to seperate each
 item so they can be parsed seperately and understood to be 
room and direction. Again, we can't use "exit" because Common Lisp
already uses this |#

#| now we establish what we want "world" to be, This will hold our room name
    as well as our direction for that room. We can use this to check that the direction we
    want to go in is correct, and it can be used to guide our player to the correct room
    as well |#

(defparameter  *world* '(room  direction))

;;; Now, isolate the second parameter in world, and make that our direction

(defparameter *direction* (cdr *world*))               

;;; Now, make the room name the first word in the paramter world

(defparameter *room* (car  *world*)


 #| Now we set up the prompt - this will loop throughout the program unless we exit
     it.  Dying in this game automatically exits us, so we don't have to look for that,
     this only needs to look for exit. We'll set it up to look for inputs as well, and unless
     an acceptable input is entered we'll return to this prompt. |#


  (defun *prompt*
    (let ((choice 1))  ; whatever choice is , let it equal "1" for right now, it's a pointer
      (format t " ~% > ") ; Let our prompt print a carriage return then display " > "
      (let ((response (read-line))) ; now we tell Common Lisp to read the input

    #| Here we need to point the prompt at the world and verify if we're 
                      given a valid choice , if we are, we can go to the next room, otherwise
                      we'll print an error message, then return to the prompt |#
    
    (if t (*direction*)
        (= *room* *NextRoom*)
        (format t "You bang your head against the wall!" (*prompt*))))))

  #| Now we set up the combat loop.  It's random, based on throws of the 
      dice - HOWEVER, the players Dexterity will be judged against the 
      gladiators dexterity, who ever has the highest dexterity, the difference will
      be removed from the strike, lessening the effect of the strike.  The difference
      will also be removed from any damage, lessening the damage as well. 
      When the player enters the room, the gladiator strikes first.
   
      A dice is rolled for the gladiator. If he meets or exceeds the players dexterity
     (pdexterity) he hits the player. If  it's less, than he misses.  If he hits, the 
     amount of damage he does will be the difference between the player's 
     health (*phealth*) and the amount over his dexterity, for example , if the 
     players health is 18 and the gladiator rolls a 20, he will have hit for 2 
     points as 20 - 18  =   2.   If  the gladiator hits (based on the dice roll) and 
     the amount is a negative number or a 0, the blow WOULD have hit, had the 
     player not dodged it.  The same rules hold true for the gladiator! |#


  #| Here we set up the functions that computes how much damage you have.
       there will be one for the player and one for the gladiator. It will allow up 
       to keep track of the current health and subtract hit points away when struck |#

(defun p_health_counter ()
  (( - *dice_combat* *pdexterity ( - *phealth))))

(defun g_health_counter ()
  (( - *dice_combat* *gdexterity ( - *ghealth))))
  

;; Here we define the player's death - this occurs if  the player's health goes to zero or below
  

(defun *pdeath* ()   
  (format t "~%Unfortunately for you, the gladiator has no mercy on you and he beheads you ~%~%~% **** You have died! **** ~%~%"))   ; prints the player death string and stops as there's no where else to go.

;; Here we define the gladiators death

(defun *gdeath* ()
  (format t "~% You offer the gladiator mercy, he responds by spitting in your face. You slit his throat. ~%~%~% **** The Gladiator has died ! **** ~%~%~% You spin around and with unerring aim, throw your sword INTO the Emporer and impale him!  ~%~%~% *** The Emperor is dead!  Long live the Emperor *** ~%~%~%. You take the Emperor\'s place and rule with justice and mercy and die a beloved emperor a century later. %~%~"))
;; You kill both the gladiator and the evil emperor that placed you there to begin with a rule justly!

(defun p_hit() ; The player's hit.  I found it easier to play the hits  and misses away from the combat loop.
  (format t "~%The gladiator hits you for %A points!" (*p_health_counter*))
      
(defun p_miss() ; this time the gladiator misses, you take no combat damage
  (format t "~% You dodge out of  the way - just in the nick of  time !"))

(defun g_hit () ;You hit the gladiator this time
  (format t "~% You hit the gladiator for %A points!" ( *g_health_counter*)))

(defun g_miss() ;You miss the gladiator and do no damage
  (format t "~% The gladiator dodges out of  the way and laughs at your failed attempt to hit him!"))
 
  
 (defun *combat* ()
    (loop while (or ( <= 0 *phealth*) (<= 0 *ghealth*))  ; if either that player or the gladiators health is zero or lower, the game ends with their death, otherwise, keep fighting
        (*dice_combat*) ; roll *dice_combat* to see if  the swing is a hit or miss

        #| The gladiator swings first, his roll must meet or exceed
                                         the player's dexterity in order to actually hit the player |#
        
            (if ( >= *dice_combat* *pdexterity* 
            (p_hit ( = *phealth* *p_health_counter*)) ;remove hp 
            (p_miss ( -  *phealth* 0 )))) ; missed , no hp removed

      #|  Now the player swings, same rules as before |#

        (if ( >= *dice_combat* *gdexterity*
             (g_hit ( = *gheath* *g_health_counter*)) ;remove hp
             (g_miss ( - *ghealth* 0)))))) ;player missed, no hp removed


  #| Now we set up the rooms, it's going to be two rooms, the syntax for this command 
      was already set up in the function on line 165, "(defparameter *world*)". It will 
      have the room followed by the direction, for example  (forest south). That means
      that if  the player types "south", he'll go to the forest. The rooms have to be coded
      in reverse, so the first room we'll code will be the last room we enter. In this case
      it's going to be the arena, the second room will be the training room where our
      player will be allowed to only go south. |#

  
;; First we create the training room        
                  
 (defun training_room 
     (format t " ~%~% .......So, you got plastered at the emperor's banquet \(and to be quite honest,  your head still aches from too much wine \), you insulted the Emperor by wearing a mask with an immense nose on it and pretending you were him. The Emperor roared in anger and sentenced you to die in the arena, for his amusement. The door to the arena stands open to the south and I'm afraid it/'s the only way you can go, the door to the north is locked and you have no chance of opening that door whatsoever ~%")
   (defun *world* arena south))

  ;; Now we create the arena - in this room, the gladiator will fight you automatically

  (defun arena
      (format t "~%~% The Arena of Quendor rises before you. It was in this very arena that the famous gladiator Dimwit Flathead slayed the fabled slavering Grue.  THIS time, it's YOU facing Dimwit Flathead the XIV. He towers over you and looks like he can break you in half with his fingers. He holds a longsword, as  do you.  In astonishing speed he wields his sword and swings.........~%")
    (*combat*)) ; this starts the combat automatically.

  ;; last thing to do is to tell Common Lisp what function to run first - that 
  ;; will be the training room.
  
    (training_room)
  

感谢您的协助!

您的代码

(defparameter *room* (car  *world*)

缺少右括号,这就是错误实际告诉您的内容:表单没有在 EOF 之前结束。

请注意,您发送的代码 let 语法不正确。 记住,parens in lisp and scheme are meaningful.