Skip to content

Commit

Permalink
update: src/lisperati
Browse files Browse the repository at this point in the history
  • Loading branch information
netpyoung committed Jan 16, 2024
1 parent 43a50d8 commit 461ca86
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 25 deletions.
7 changes: 4 additions & 3 deletions src/lisperati/01_casting.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

- [원문](https://www.lisperati.com/casting.html)

Lisp를 만져본 사람이라면, 이 언어는 다른 프로그래밍 언어들과 매우 다르다고 말할 것입니다.
실로 놀라운 방식으로 많이 다릅니다.
이 만화책을 통해 Lisp의 독특한 디자인이 어떻게 이 언어를 강력하게 만드는지 배울 수 있습니다
리스프(Lisp, 리슾)를 아는 사람이라면, 리스프가 다른 프로그래밍 언어들과 매우 다르다고 말할 것입니다.
이는 실로 놀라울 정도로 많이 다릅니다. 이 만화를 통해 리스프가 얼마만큼 강력한지, 리스프의 독특한 디자인을 통해 배워보도록 하겠습니다.

![](../res/different.jpg)

리스프 언어에는 여러가지 종류가 있는데, 그 중 클로저로 진행하도록 하겠습니다.

`clj` 명령어를 통해 클로저의 REPL을 실행합니다.

Expand Down Expand Up @@ -43,5 +43,6 @@ REPL을 종료하려면

## 짚고넘어갈것

- [클로저(Clojure)](https://clojure.org)
- clj 명령어
- REPL 종료법
8 changes: 5 additions & 3 deletions src/lisperati/02_syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

모든 컴퓨터 언어는 **신택스(Syntax, 문법/구조론)****시맨틱(Semantic, 의미론)** 으로 이루어진 코드를 가지고 있습니다.

프로그래밍 언어의 신택스는 기본 골격입니다. 컴파일러가 프로그램에서 무엇이 무엇인지 알 수 있도록 프로그램이 따라야만 합니다. 이로써 무엇이 함수인지, 변수인지 등을 알 수 있습니다. 프로그램의 시맨틱은 좀 더 "랜덤"한 내용을 다룹니다. 무엇이 사용가능한 명령어인지, 프로그램의 특정 지점에서 어떤 변수가 허용되는지와 같은 것들이 있습니다.
**신택스** 는 프로그램에서 컴파일러가 무엇이 무엇인지 알 수 있도록 따라야만 하는 프로그래밍 언어의 기본 빼대입니다. 이로써 무엇이 함수인지, 변수인지 등을 알 수 있습니다.

**시맨틱** 은 프로그램의 좀 더 "랜덤"한 내용을 다룹니다. 프로그램의 특정 지점에서 어떤 변수가 사용가능한지 아닌지 같은 것들이 있습니다.

| syntax & semantics | |
| ------------------ | ------------------------ |
| Syntax | 어떻게 구성되어야 하는가 |
| Semantics | 어떻게 동작하는가 |

리스프(Lisp, 리슾)의 첫 번째로 특별한 부분은 주요 프로그래밍 언어 중 가장 간결한 신택스를 가지고 있다는 점입니다. 기본적으로 리스프 신택스는 리스프 컴파일러에게 넘겨주는 텍스트를 리스트(list)로 넘기도록 강제합니다. 필요에 따라 중첩된 리스트 역시 가능합니다.
리스프의 첫 번째로 특별한 부분은 메이저 프로그래밍 언어 중 가장 간결한 신택스를 가지고 있다는 점입니다. 기본적으로 리스프 신택스는 리스프 컴파일러에게 넘겨주는 텍스트를 리스트(list)로 넘기도록 강제합니다. 필요에 따라 중첩된 리스트 역시 가능합니다.

리스트의 시작과 끝은 괄호로 되어있습니다:

Expand All @@ -23,7 +25,7 @@

![](../res/list.jpg)

추가적으로, 리스프 컴파일러는 코드를 읽을때 두가지 모드를 사용합니다: 코드 모드와 데이터 모드
추가적으로, 리스프 컴파일러는 두가지 모드를 사용하여 코드를 읽습니다: 코드 모드와 데이터 모드

데이터 모드일때, 리스트에 아무거나 넣을 수 있습니다. 그러나, 컴파일러는 코드 모드에서 코드를 읽기 시작합니다.

Expand Down
10 changes: 5 additions & 5 deletions src/lisperati/03_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

![](../res/world.jpg)

단순한 게임에는 3개의 다른 장소가 있습니다: `거실``다락방`을 가진 집이 있으며 그리고 `정원`도 있습니다.
간단한 게임에는 3개의 다른 장소가 있습니다: `거실``다락방`을 가진 집이 있으며 그리고 `정원`도 있습니다.

이제 게임 세상을 표현하는 `상수_전체지도`라는 새로운 변수를 정의해 봅시다:

Expand Down Expand Up @@ -67,8 +67,7 @@
| 벡터(vector) | `[ ]` | `[1 2 3]` | O(1) |
| 사전(dictionary, 딕션어리) | `{ }` | `{:a 1 :b 2 :c 3}` | O(1) |



그리고 문자열은 따옴표(`" "`)로 둘러싸여 있습니다.

이제 지도와 오브젝트 목록이 있으니, 각각의 오브젝트가 지도상의 장소 어디에 있는지 알 수 있는 변수를 선언해 봅시다:

Expand Down Expand Up @@ -100,6 +99,7 @@
- [def](https://clojuredocs.org/clojure.core/def)
- 키워드(`:`)
- 리스트(`( )`)
- 데이터를 간결하게 추리기
- 벡터(`[ ]`)
- 사전(`{ }`)
- 벡터(`[ ]`)
- 문자열(`" "`)
- 데이터를 간결하게 추리기
2 changes: 1 addition & 1 deletion src/lisperati/04_looking.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

- [원문](https://www.lisperati.com/looking.html)

이제 게임 커맨드를 만들어 보도록 하겠습니다.
이제 게임에 사용할 게임 커맨드들을 만들어 보도록 하겠습니다.

가장 먼저 필요한 게임 커맨드는 현재 있는 장소에 대해 알려주는 `둘러보기` 커맨드입니다.
그렇다면 게임 세상에서의 장소를 설명하는 커맨드에 어떤 정보들을 넣어야 할까요?
Expand Down
4 changes: 2 additions & 2 deletions src/lisperati/05_walking.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
- [원문](https://www.lisperati.com/walking.html)


이제 세상을 볼 수 있게 되었으니 안에서 걸어 다닐 수 있는 코드를 작성해 보겠습니다.
편의상 상태를 변경하는 함수 이름의 끝에 `!`를 붙이도록 하겠습니다.
이제 게임 세상에 무엇이 있는지 알 수 있게 되었으니, 이 안에서 걸어 다닐 수 있는 코드를 작성해 보겠습니다.
편의상 상태를 변경하는 (사이드 이펙트)함수 이름의 끝에 `!`를 붙이도록 하겠습니다.

함수형 스타일이 아닌 사이드 이펙트를 지닌 `방향으로걷기!` 함수는 방향을 지정하고 그 방향으로 걸어갈 수 있게 해줍니다.

Expand Down
4 changes: 2 additions & 2 deletions src/lisperati/06_spels.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

- [원문](https://www.lisperati.com/spels.html)

이제 리스프의 놀랍도록 강력한 기능을 배워보겠습니다: SPEL 만들기!
자, 이제 리스프의 놀랍도록 강력한 기능을 배워보겠습니다: SPEL 만들기!

스펠(마법, `SPEL`)은 `S`emantic `P`rogram `E`nhancement `L`ogic의 줄임말로, 컴퓨터 코드의 세계 내부에 새로운 동작을 생성하여 필요에 맞게 동작을 사용자 정의하기 위해 기본적인 수준에서 Lisp 언어를 변경하는 것으로, Lisp에서 가장 마법처럼 보이는 부분입니다.
스펠(마법, `SPEL`)은 `S`emantic `P`rogram `E`nhancement `L`ogic의 줄임말로, :TODO 컴퓨터 코드의 세계 내부에 새로운 동작을 생성하여 필요에 맞게 동작을 사용자 정의하기 위해 기본적인 수준에서 Lisp 언어를 변경하는 것으로, 리스프에서 가장 마법처럼 보이는 부분입니다.
스펠을 사용하려면 먼저 리스프 컴파일러 내에서 스펠을 활성화 시켜야 합니다.

``` clojure
Expand Down
23 changes: 14 additions & 9 deletions src/lisperati/07_actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

- [원문](https://www.lisperati.com/actions.html)

이제 할 일이 하나만 더 남았으니 게임이 완성됩니다: 플레이어가 게임에서 승리하기 위해 수행해야 하는 몇 가지 특별한 행동을 게임에 추가하세요. 첫 번째 커맨드은 플레이어가 다락방에 있는 양동이에 체인을 용접하는 것입니다:
이제 한단계만 더 넘으면 게임이 완성됩니다: 플레이어가 게임에서 승리하기 위해 수행해야 하는 몇 가지 특별한 행동을 게임에 추가합니다.
첫 번째 커맨드는 다락방에 있는 양동이에 사슬을 용접하는 것입니다:

``` clojure
(defn 용접 [오브젝트 대상]
Expand All @@ -20,7 +21,7 @@
```


먼저 이 작업을 이미 수행했는지 여부를 알 수 있는 새로운 전역 변수를 만들었습니다. 다음으로 용접에 적합한 조건이 모두 갖추어졌는지 확인하고 용접할 수 있는 용접 함수를 만듭니다.
먼저 이 작업을 이미 수행했는지 여부를 알 수 있는 새로운 전역 변수를 만들었습니다. 다음으로 용접에 적합한 조건이 모두 갖추어졌는지 확인하고 용접할 수 있는 용접 커맨드를 만들었습니다.

![](../res/weld.jpg)

Expand All @@ -32,9 +33,9 @@
["그렇게 용접 할 수는 없습니다"]
```

이런... 우리는 양동이나 체인이 없습니다. 그리고 주위에 용접할만 장치도 없습니다... 뭐 괜찮습니다...
이런... 우리는 양동이나 사슬이 없습니다. 그리고 주위에 용접할만 장치도 없습니다... 뭐 괜찮습니다...

이제 체인을 건 양동이로 우물을 기르는 커맨드를 만들어 봅시다:
이제 사슬을 건 양동이로 우물을 기르는 커맨드를 만들어 봅시다:


``` clojure
Expand All @@ -51,7 +52,7 @@
["`양동이`에 물을 가득 채웠습니다."]))))
```

주의깊게 살펴봤다면 이 커맨드가 앞선 `용접` 커맨드와 매우 유사하다는 것을 알 수 있습니다... 두 커맨드 모두 오브젝트, 대상, 장소를 확인하는데 두 커맨드를 하나의 함수로 합치기에는 무리처럼 보입니다. 유감스럽습니다... ...만 리스프이기에 단순히 함수를 추가시켜 나가는게 아니라, 스펠을 외울 수 있습니다! 다음 스펠을 만들어 봅시다:
눈치챘는지 모르겠지만 이 커맨드가 앞선 `용접` 커맨드와 매우 유사하다는 것을 알 수 있습니다... 두 커맨드 모두 오브젝트, 대상, 장소를 확인하는데 두 커맨드를 하나의 함수로 합치기에는 무리처럼 보입니다. 유감스럽습니다... ...만 리스프이기에 단순히 함수를 추가시켜 나가는게 아니라, 스펠을 외울 수 있습니다! 다음 스펠을 만들어 봅시다:

``` clojure
(def-스펠 def-액션 [커맨드명 [액션오브젝트 액션대상] 액션장소 & 액션본체]
Expand All @@ -68,7 +69,7 @@
~@'~액션본체)))))
```

헛웃음이 나올 정도로 복잡한 스펠입니다. 따옴표, 역따옴표, 쉼표 및 기타 이상한 기호(`#`, \`, `~`, `~@`)가 // 목록을 흔드는 것보다 더 많이 포함되어 있습니다.
헛웃음이 나올 정도로 복잡한 스펠입니다. 따옴표, 역따옴표, 쉼표 및 기타 이상한 기호(`#`, \`, `~`, `~@`)가 :TODO // 목록을 흔드는 것보다 더 많이 포함되어 있습니다.
뿐만 아니라 스펠이 스펠을 만들고 있습니다!
숙련된 리스프 프로그래머라도 이런 괴물을 만들기 위해선 약간의 고민을 해야 할 것입니다.

Expand All @@ -90,8 +91,8 @@
["`사슬`이 `양동이`에 단단히 용접되었습니다."])))
```

커맨드가 얼마나 쉽게 이해할 수 있게 됬는지 보세요. 액션 스펠을 사용하면 원하는 내용을 간결하고 정확하게 작성할 수 있습니다. 마치 게임 커맨드를 만들기 위해 자신만의 컴퓨터 언어를 만든 것과 같습니다.
스펠로 자신만의 의사 언어를 만드는 것을 **도메인 특정 언어 프로그래밍(DSL, Domain Specific Language)** 이라고 하는데, 이는 빠르고 우아하게 프로그래밍할 수 있는 매우 강력한 접근법입니다.
이 얼마나 쉽게 이해할 수 있게 됬나요. 액션 스펠을 사용하면 원하는 내용을 간결하고 정확하게 작성할 수 있습니다. 마치 게임 커맨드를 만들기 위해 자신만의 컴퓨터 언어를 만든 것과 같습니다.
스펠과 같이 자신만의 의사 언어를 만드는 것을 **도메인 특정 언어 프로그래밍(DSL, Domain Specific Language)** 라고 하는데, 이는 빠르고 우아하게 프로그래밍 할 수 있는 매우 강력한 접근법입니다.

``` clojure
> (용접 사슬 양동이)
Expand Down Expand Up @@ -139,19 +140,23 @@
"성공! 게임 끝."]))
```

- `cond`는 if와 비슷하지만 여러가지 조건과 행동을 가질 수 있습니다.
- ex) `(cond (= 1 2) "1과 2는 같습니다." (= 1 1) "1과 1은 같습니다." :else "모든 조건이 거짓입니다.")` -> `"1과 1은 같습니다."`

![](../res/donut.jpg)


**마침내 텍스트 어드벤처 게임이 완성되었습니다!**

- 게임에 대한 전체 공략을 보려면 [여기](./09_cheat.md)를 클릭합니다.
- 소스 코드의 사본을 보려면 [여기]()를 클릭합니다.
- 소스 코드의 사본을 보려면 [여기](../code/src/spel.clj)를 클릭합니다.

이 튜토리얼을 최대한 간단하게 만들기 위해 리스프의 동작 방식에 대한 세부 사항들을 건너띄었으므로, 이제 그것들이 무엇인지 한번 살펴 보도록 하겠습니다...

## 짚고넘어갈것

- [and](https://clojuredocs.org/clojure.core/and)
- [str](https://clojuredocs.org/clojure.core/str)
- [cond](https://clojuredocs.org/clojure.core/cond)
- nested macro
- 도메인 특정 언어 프로그래밍(DSL, Domain Specific Language)

0 comments on commit 461ca86

Please sign in to comment.