# 주문을 걸기 (Casting SPELs)
Now we're going to learn an incredibly powerful feature of Lisp: Creating SPELs!
이제 Lisp의 놀랍도록 강력한 기능을 배워보겠습니다. 바로 스펠 만들기입니다!
SPEL is short for "Semantic Program Enhancement Logic" and lets us create new behavior inside the world of our computer code that changes the Lisp language at a fundamental level in order to customize its behavior for our needs- It's the part of Lisp that looks most like magic. To enable SPELs, we first need to activate SPELs inside our Lisp compiler ( Don't worry about what this line does - Advanced Lispers should click here. (opens new window) )
SPEL은 "시맨틱 프로그램 향상 논리"의 줄임말로, 컴퓨터 코드의 세계 내부에 새로운 동작을 생성하여 필요에 맞게 동작을 사용자 지정하기 위해 기본적인 수준에서 Lisp 언어를 변경할 수 있게 해 줍니다. SPEL을 활성화하려면 먼저 Lisp 컴파일러 내에서 SPEL을 활성화해야 합니다(이 줄의 기능에 대해 걱정하지 마세요. 고급 Lisp 사용자는 여기를 클릭하세요.).
(defmacro defspel [& rest] `(defmacro ~@rest))
Ok, now that they're enabled, let's cast our first spell, called walk
:
이제 기능이 활성화되었으니 첫 번째 주문인 'walk
'를 사용해 보겠습니다:
(defspel walk [direction] `(walk-direction '~direction))
What this code does is it tells the Lisp compiler that the word walk
is not actually the word walk
but the word walk-direction
and that the word direction
actually has a quote in front of it, even though we can't see it. Basically we can sneak in some special code inbetween our program and the compiler that changes our code into something else before it is compiled:
이 코드가 하는 일은 걷는다는 단어가 실제로는 걷는다는 단어가 아니라 걷는 방향이라는 단어이며, 우리가 볼 수는 없지만 실제로는 방향이라는 단어 앞에 따옴표가 있다는 것을 Lisp 컴파일러에게 알려주는 것입니다. 기본적으로 프로그램과 컴파일러 사이에 코드를 컴파일하기 전에 코드를 다른 것으로 변경하는 특수 코드를 몰래 삽입할 수 있습니다.
Notice how similar this function looks to the code we had written before for describe-path: In Lisp, not only do code and data look a lot identical, but code and special commands to the compiler (the SPELs) look identical as well - A very consistent and clean design! Let's try our new spell:
이 함수가 이전에 설명 경로에 대해 작성했던 코드와 얼마나 유사한지 주목하세요: Lisp에서는 코드와 데이터가 거의 동일하게 보일 뿐만 아니라 코드와 컴파일러에 대한 특수 명령(SPEL)도 동일하게 보입니다. 매우 일관되고 깔끔한 디자인입니다! 새로운 스펠을 사용해 봅시다:
(walk east)
user=> (walk east)
(you are in the living room of a wizards house -
there is a wizard snoring loudly on the couch -
there is a door going west from here -
there is a stairway going upstairs from here -
you see a whiskey-bottle on the floor -
you see a bucket on the floor -)
much better!
훨씬 좋아보입니다!
Now we'll create a command to pickup objects in our world:
이제 월드에서 오브젝트를 픽업하는 명령을 만들어 보겠습니다.
(defn pickup-object [object]
(cond (is-at? object location object-locations)
(do
(def object-locations (assoc object-locations object 'body))
`(you are now carrying the ~object))
:else '(you cannot get that.)))
This function checks to see if the object is indeed on the floor of the current location - If it is, it pushes the new location (the player's body) onto the list (pushing means to add a new item to the list, in a way that the assoc command sees and therefore hides the previous location) and returns a sentence letting us know wether it succeeded.
이 함수는 오브젝트가 실제로 현재 위치의 바닥에 있는지 확인하고, 만약 그렇다면 새 위치(플레이어의 몸)를 목록에 밀어넣고(밀어넣는다는 것은 목록에 새 항목을 추가하는 것을 의미하며, assoc 명령이 이전 위치를 보고 숨기는 방식입니다) 성공 여부를 알려주는 문장을 반환합니다.
Now let's cast another SPEL to make the command easier to use:
이제 명령을 더 쉽게 사용할 수 있도록 다른 주문을 시전해 보겠습니다:
(defspel pickup [object] `(spel-print (pickup-object '~object)))
Now let's try our new SPEL:
이제 새로운 스펠(SPEL)을 사용해 보겠습니다:
(pickup whiskey-bottle)
user=> (pickup whiskey-bottle)
(you are now carrying the whiskey-bottle)
Now let's add a couple more useful commands - First, a command that lets us see our current inventory of items we're carrying:
이제 몇 가지 유용한 명령을 추가해 보겠습니다. 먼저, 현재 가지고 있는 아이템의 인벤토리를 확인할 수 있는 명령입니다:
(defn inventory []
(filter (fn [x] (is-at? x 'body object-locations)) objects))
Now a function that tells us if he have a certain object on us:
이제 특정 물체를 가지고 있는지 알려주는 함수가 있습니다:
(defn have? [object]
(some #{object} (inventory)))