<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Dear All,<div><br></div><div>I almost finish the chapter 3 of Real World Haskell. The last exercise blocks me. My code will crash while running. Does anyone can tell me which part is wrong in my code? Thanks.</div><div><br></div><div>Question:</div><div><span class="Apple-style-span" style="font-family: verdana, sans-serif; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; ">Using the code from the preceding three exercises, implement Graham's scan algorithm for the convex hull of a set of 2D points. You can find good description of what a&nbsp;<a class="ulink" href="http://en.wikipedia.org/wiki/Convex_hull" target="_top">convex hull</a>. is, and how the&nbsp;<a class="ulink" href="http://en.wikipedia.org/wiki/Graham_scan" target="_top">Graham scan algorithm</a>&nbsp;should work, on&nbsp;<a class="ulink" href="http://en.wikipedia.org/" target="_top">Wikipedia</a>.</span><br><div><div><br class="webkit-block-placeholder"></div><div>Answer:</div><div><br></div><div><div>-- Graham Scan, get the convex hull.</div><div>-- Implement the algorithm on <a href="http://en.wikipedia.org/wiki/Graham_scan">http://en.wikipedia.org/wiki/Graham_scan</a></div><div><br></div><div>import Data.List</div><div>import Data.Ord</div><div><br></div><div>data Direction = TurnLeft | TurnRight | GoStraight deriving (Eq, Show)</div><div><br></div><div>-- Determine if three points constitute a "left turn" or "right turn" or "go straight".</div><div>-- For three points (x1,y1), (x2,y2) and (x3,y3), simply compute the direction of the cross product of the two vectors defined by points (x1,y1), (x2,y2) and (x1,y1), (x3,y3), characterized by the sign of the expression (x2 − x1)(y3 − y1) − (y2 − y1)(x3 − x1). If the result is 0, the points are collinear; if it is positive, the three points constitute a "left turn", otherwise a "right turn".</div><div>direction a b c = case compare ((x2 - x1) * (y3 - y1)) ((y2 - y1) * (x3 - x1)) of</div><div>&nbsp;&nbsp; &nbsp;EQ -&gt; GoStraight</div><div>&nbsp;&nbsp; &nbsp;GT -&gt; TurnLeft</div><div>&nbsp;&nbsp; &nbsp;LT -&gt; TurnRight</div><div>&nbsp;&nbsp; &nbsp;where &nbsp; x1 = fst a</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;y1 = snd a</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x2 = fst b</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;y2 = snd b</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x3 = fst c</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;y3 = snd c</div><div><br></div><div>grahamScan points = scan (sort points)</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-- For each point, it is determined whether moving from the two previously considered points to this point is a "left turn" or a "right turn". If it is a "right turn", this means that the second-to-last point is not part of the convex hull and should be removed from consideration. This process is continued for as long as the set of the last three points is a "right turn". As soon as a "left turn" is encountered, the algorithm moves on to the next point in the sorted array. (If at any stage the three points are collinear, one may opt either to discard or to report it, since in some applications it is required to find all points on the boundary of the convex hull.)</div><div>&nbsp;&nbsp; &nbsp;where &nbsp; scan (a : (b : (c : points)))</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| (direction a b c) == TurnRight &nbsp; &nbsp;= scan (a : (c : points))</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| otherwise &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = a : (scan (b : (c : points)))</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;scan (a : (b : [])) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = []</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-- Put prime to the head.</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sort points &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = prime : (reverse (sortBy (compareByCosine prime) rest))</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-- Sort a list to compute. The first step is to find a point whose y-coordinate is lowest. If there are more than one points with lowest y-coordinate, take the one whose x-coordinate is lowest. I name it prime.</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;where &nbsp; compareByYAndX a b</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| compareByY == EQ &nbsp;= comparing fst a b</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| otherwise &nbsp; &nbsp; &nbsp; &nbsp; = compareByY</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;where &nbsp; compareByY &nbsp;= comparing snd a b&nbsp;</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;prime &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = minimumBy compareByYAndX points</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-- Delete prime from the candidate points. Sort the rest part by the cosine value of the angle between each vector from prime to each point. Reverse it and put prime to the head.</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rest &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= delete prime points</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;compareByCosine p a b &nbsp; = comparing cosine pa pb</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;where &nbsp; pa &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= (fst a - fst p, snd a - snd p)</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pb &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= (fst b - fst p, snd b - snd p)</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cosine v &nbsp; &nbsp;= x / sqrt (x ^ 2 + y ^ 2)</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;where &nbsp; x = fst v</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;y = snd v</div></div><div><br></div><div>
<div><br class="Apple-interchange-newline">Best regards,<br class="Apple-interchange-newline">Zhi-Qiang Lei</div><div><a href="mailto:zhiqiang.lei@gmail.com">zhiqiang.lei@gmail.com</a></div>
</div>
<br></div></div></body></html>