윌슨의 미로 발생기 알고리즘 :
-
임의의 좌표를 골라서 방문 표시한다.
-
방문하지 않은 임의의 좌표를 고른다 – 만약 없다면 미로 출력
-
2에서 고른 좌표에서 출발하여 방문 표시된 위치까지 랜덤 걷기한다 – 랜덤 걷기 중 한 위치를 2번 이상 지난다면, 항상 그 방향을 기억한다.
-
랜덤 걷기한 모든 위치를 방문 표시하고, 출구 방향에 따라 벽을 제거한다.
-
2로 돌아간다.
아래는 윌슨 알고리즘을 클로저로 구현한 코드이다. (Clojure Programming p.147에서 인용)
이 코드를 당장 이해할 필요는 없다. 아래는 윌슨의 미로 발생기 알고리즘을 구현한 클로저 코드와 자연어(한글) 기술을 라인별 일대일 매칭 관계를 보여준다.
|
클로저 구현 코드 |
자연어(한글) 기술 |
|
|
1줄 |
(defn maze [walls] |
X |
|
2줄 |
(let [paths (reduce (fn [index [a b]] |
X |
|
3줄 |
(merge-with into index {a [b] b [a]})) |
X |
|
4줄 |
{} (map seq walls)) |
X |
|
5줄 |
start-loc (rand-nth (keys paths))] |
윌슨 1: 임의의 좌표를 골라서 |
|
6줄 |
(loop [walls walls |
X |
|
7줄 |
unvisited (disj (set (keys paths)) start-loc)] |
윌슨 1: 방문 표시한다. |
|
8줄 |
(if-let [loc (when-let [s (seq unvisited)] (rand-nth s))] |
윌슨 2: 방문하지 않은 임의의 좌표를 고른다. |
|
9줄 |
(let [walk (iterate (comp rand-nth paths) loc) |
윌슨 3: 랜덤 걷기 수행. |
|
10줄 |
steps (zipmap (take-while unvisited walk) (next walk))] |
윌슨 3: 방문 표시된 위치까지 |
|
11줄 |
(recur (reduce disj walls (map set steps)) |
윌슨 4: 벽 제거 |
|
12줄 |
(reduce disj unvisited (keys steps)))) |
윌슨 4: 방문 표시한다. |
|
13줄 |
walls)))) |
윌슨 2: 만약 없다면 미로 출력 |
위 표에서 X로 표시된 것은 클로저 코드 라인중에서 윌슨의 알고리즘을
자연어(한글)로 표기한 문장에서 표현되지 않은 것을 나타내는데, 단지 전체 클로저 코드 라인 13개 라인중에서 5개 뿐이다. 즉
자연어와 무관하게 프로그래밍 언어 그 자체만을 위한 코드 라인은 5개 뿐이고, 나머지 8개 라인은 자연어의 표현을 그대로 클로저
코드로 표현하고 있는 것이다. 이것은 클로저 코드는 인간의 자연어에 비견되는 수준의 추상화 로 프로그래밍 코드를 만들어 낼 수
있다는 것을 보여준다.
이처럼 클로저는 그 표현력이 매우 뛰어나고 코드의 길이가 매우 짧다. (함수형 언어를 접해본 경험이 없는) 자바나 C++ 프로그래머들이 클로저를 공부하면서 느끼게 되는 것은 ‘어떻게 이렇게 짧은 코드로 그 많은 것을 표현할 수 있지? 도대체 이 코드들에는 버그가 들어설 자리조차 없어 보인다’ 라는 것이다.
클로저의 이러한 특성은 복잡성을 제거하고 단순성을 최대화하는 것에 역점을 두고 프로그래밍 언어 설계시에 언어의 구성에 필요한 패러다임 요소들을 선택했기 때문이다.
언어 자체가 버그를 지니고 있으면 어떡함?