-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch09.tex
115 lines (83 loc) · 5.18 KB
/
ch09.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
\chapter{\Large{Interactive programs}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\exercise{9.1}
기존의 $getLine$ 함수를 사용하여 입력할 때, 삭제 키를 누르면 (ANSI
터미널에서는) `\texttt{\^{}?}'와 같은 문자열이 입력되어 버린다. 이를 제대로
처리하기 위해서는 입력이 `\texttt{\textbackslash DEL}' 경우를 구분하여 다음과
같이 처리해줘야 한다.
\begin{itemize}
\item $getLine$ 함수에서 쓰인 $getChar$ 함수는 문자가 입력되자마자 그 문자가
화면에 출력되는데, 삭제 키에 대한 문자는 화면에 출력되어선 안되므로
$readLine$ 함수에서 쓰기엔 적합하지 않다. 대신에
$getCh$ 함수를 사용하고, 입력이 `\texttt{\textbackslash DEL}'이 아닌
경우에만 입력을 화면에 출력하도록 수정한다.
\item 만일 입력이 `\texttt{\textbackslash DEL}'이라면, 바로 전까지 입력된
문자열에서 가장 마지막의 입력을 버리고서 계속 입력을 받아야 한다. 즉,
작성하고자하는 함수는 이제까지 입력된 문자열이 무엇인지 알아야 한다. 따라서
보조함수 $readLine1 :: String \rightarrow IO String$을 작성하고, $readLine$
함수는 이 보조함수를 사용하도록 한다.
\item 입력이 `\texttt{\textbackslash DEL}' 일 때는 (1) 우선 뒤로 한 칸 움직이고,
(2) 빈 공백 하나를 출력하여 문자를 지운 후, (3) 다시 뒤로 한 칸 움직인 다음,
(4) 이제까지 입력된 문자열에서 꼬리만을 가지고 $readLine1$을 재귀 호출하면 된다.
\end{itemize}
다음은 구현된 코드이다.
\haskell[10]{./src/ch09-ex01.hs}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\exercise{9.2}
파싱이 실패한 지점 바로 위에 `\texttt{v}'를 출력하여 오류 위치를 쉽게 파악할
수 있게 해보자. 우선 다음과 같이 오류 위치를 표시하는 함수와 표시된 위치를
없애는 함수를 작성한다.
\haskellpart{./src/ch09-ex02.hs}{164}{170}
그리고 나서 $eval$ 함수에서 계산이 실패한 경우에 파싱되지 못한 문자열을 통해
오류 위치를 계산한 후 표시하도록 수정한다.
\haskellpart{./src/ch09-ex02.hs}{200}{205}
마지막으로 표시된 오류 위치가 계속 남아있으면 보기에 좋지 않으므로, 특정 키가
눌리면 이전에 표시한 오류 위치가 사라지도록 $calc$ 함수를 수정한다.
\haskellpart{./src/ch09-ex02.hs}{172}{180}
다음은 구현된 계산기에서 잘못된 계산식인 ``\texttt{3+4//6}''을 입력하고 리턴을
누른 후의 모습 중 일부이다. 적절한 오류 위치가 표시됨을 볼 수 있다.
\begin{lstlisting}
+----v----------+
| 3+4//6 |
\end{lstlisting}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\exercise{9.3}
문제에서 제시된 방식대로 구현하기 위해서는 게임판을 그릴 때 바로 이전의
게임판 또한 알고 있어야 한다. 따라서 새로운 보조 함수 $life1~::~Board
\rightarrow Board \rightarrow IO~()$을 작성하고 $life$는 이 함수를 사용하도록
수정한다. 그리고 실제 게임판을 그리는 함수인 $showcells$ 역시 이전 게임판 또한
인자로 받도록 수정한다.
다음은 수정된 $showcells$ 함수이다. 이전 게임판에서 없다가 이번 게임판에서
새로 생긴 위치($bc$)와 이전엔 있다가 이번에 사라진 위치($dc$) 각각을 찾고,
전자에 대해서는 `\texttt{o}'를, 후자에 대해서는 빈 칸을 출력한다.
\haskellpart{./src/ch09-ex03.hs}{29}{32}
앞의 함수를 사용하여 재귀적으로 게임을 수행하는 보조 함수 $life1$을
작성한다. 화면을 지우는 $cls$ 함수를 호출하지 않음에 유의한다.
\haskellpart{./src/ch09-ex03.hs}{71}{75}
마지막으로 함수 $life$를 다음과 같이 수정한다.
\haskellpart{./src/ch09-ex03.hs}{67}{69}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\exercise{9.4}
\haskell[42]{./src/ch09-ex04.hs}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\exercise{9.5}
\GTK\footnote{\URL{http://www.gtk.org/}} 용 UI 디자인 프로그램인
\textsf{Glade}\footnote{\URL{http://glade.gnome.org/}}와 \HASKELL에서 \GTK를
사용할 수 있도록 해주는
\textsf{Gtk2Hs}\footnote{\URL{http://www.haskell.org/gtk2hs/}}를 사용하면
쉽게 GUI를 구현할 수 있다. 다음 디렉토리에 있는 코드를 참고하기 바란다.
\begin{itemize}
\item \texttt{src/ch09-ex05}
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\exercise{9.6}
다음은 구현된 Nim 게임 프로그램이다. 프로그램을 수행하면 커서가 첫 행 맨 앞에
위치하게 되는데, 여기서 \texttt{w},\texttt{s}키로 커서를 이동한 후
\texttt{Enter}키를 누르면 별을 뽑고자 하는 행을 선택할 수 있다. 그리고서
\texttt{a}, \texttt{d}키로 뽑고자 하는 별의 갯수를 정한 후 \texttt{Enter}키로
선택하면 다음 플레이어의 턴으로 넘어가게 된다.
\haskell[28]{./src/ch09-ex06.hs}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "master"
%%% End: