Determine whether path A→B→C on a plane constitutes a left or right turn I have recently started learning functional programming and Haskell. I have encountered this problem:


  Consider three two-dimensional points a, b, and c. If we look at the angle formed by the line segment from a to b and the line segment from b to c, it either turns left, turns right, or forms a straight line. Define a Direction data type that lets you represent these possibilities. Write a function that calculates the turn made by three 2D points and returns a Direction.


I have heard that one of the goals of the Haskell language is to create elegant solutions.

This is my solution:

data Direction = LeftTurn | RightTurn | Straight deriving Show

findDirection (x, y) (x1, y1) (x2, y2) 
    | (x, y) == (x1, y1)          = Straight
    | (x1, y1) == (x2, y2)        = Straight
    | (x, y) == (x2, y2)          = Straight
    | x == x1 &amp;&amp; x1 == x2         = Straight
    | x1 == x &amp;&amp; y1 &gt; y &amp;&amp; x2 &gt; x = RightTurn
    | x1 == x &amp;&amp; y1 &gt; y &amp;&amp; x2 &lt; x = LeftTurn
    | x1 == x &amp;&amp; y1 &lt; y &amp;&amp; x2 &lt; x = RightTurn
    | x1 == x &amp;&amp; y1 &lt; y &amp;&amp; x2 &gt; x = LeftTurn
    | x1 &gt; x &amp;&amp; y2 &gt; y_on_line    = LeftTurn
    | x1 &gt; x &amp;&amp; y2 &lt; y_on_line    = RightTurn
    | x1 &gt; x &amp;&amp; y2 == y_on_line   = Straight
    | x1 &lt; x &amp;&amp; y2 &gt; y_on_line    = RightTurn
    | x1 &lt; x &amp;&amp; y2 &lt; y_on_line    = LeftTurn
    | x1 &lt; x &amp;&amp; y2 == y_on_line   = Straight
   where y_on_line   = slope * x2 + y_intercept
         slope       = (y1 - y) / (x1 - x)
         y_intercept = y - slope * x


This looks like it is too long to be considered an elegant solution.
Welcome to Haskell (and Code Review). Your ADT Direction is a good approach for the result. However, top-level functions should have a type, as it will make type errors easier to read and give other users an idea how to use your function:

type Point2 = (Double, Double)

findDirection :: Point2 -&gt; Point2 -&gt; Point2 -&gt; Direction    
findDirection (x, y) (x1, y1) (x2, y2)


While isn't necessary&mdash;GHC can infer it&mdash;it can at least act as a minimal documentation.

Next, we should tackle the names. We have x, x1 and x2. Those seem arbitrary. Why don't we start with x1? The names (ax,ay), (bx,by) and (cx,cy) would be more suitable, since we're talking about the coordinates of three specific points, a, b and c:

findDirection :: Point2 -&gt; Point2 -&gt; Point2 -&gt; Direction    
findDirection (ax, ay) (bx, by) (cx, cy)


However, as vnp said, you should use the cross product. While the cross-product is only defined for three dimensions, we can simply embed your points into \$\mathbb R^3\$ and then take the Z-component of the resulting vector:

type Vector2 = (Double, Double)

-- See https://en.wikipedia.org/wiki/Cross_product#Computing_the_cross_product
cross :: Vector2 -&gt; Vector2 -&gt; Double
cross (ax, ay) (bx, by) = error "Implement this as an exercise"


With yet another function, we can then get the two vectors from our original three points:

diff :: Point2 -&gt; Point2 -&gt; Vector2
diff (ax, ay) (bx, by) = (bx - ax, by - ay)


Now we really end up with an elegant solution:

findDirection :: Point2 -&gt; Point2 -&gt; Point2 -&gt; Direction
findDirection a b c = 
    case cross (a `diff` b) (b `diff` c) `compare` 0 of
        GT -&gt; LeftTurn
        EQ -&gt; Straight
        LT -&gt; RightTurn