Programming Praxis – Tracking Santa

In today’s Programming Praxis, our task is to calculate the total distance traveled by Santa based on data published by NORAD. Let’s get started, shall we?

First, some imports:

```import Data.List.HT
import Text.HJson
import Text.HJson.Query
```

The easiest version of the algorithm to calculate the distance between two coordinated can be found here. I’ve made a few small adjustments to get rid of some duplication. The Scheme solution rounds off the result, but I don’t believe that is correct. Granted, it doesn’t result in a big deviation (3 miles on a total of almost 200000), but rounding off should be saved until the end.

```dist :: RealFloat a => (a, a) -> (a, a) -> a
dist (lat1, lng1) (lat2, lng2) =
let toRad d = d * pi / 180
haversin x = sin (toRad \$ x / 2) ^ 2
a = haversin (lat2 - lat1) +
cos (toRad lat1) * cos (toRad lat2) * haversin (lng2 - lng1)
in 2 * 6371 * atan2 (sqrt a) (sqrt (1 - a))
```

Rather than hunting through the string ourselves for the coordinates, we use a Json library.

```coords :: Json -> [(Double, Double)]
coords = map ((\[JString lat, JString lng] -> (read lat, read lng)) .
getFromKeys ["lat", "lng"]) . getFromArr
```

The total distance can be easily calculated by summing the distances between the subsequent points of the route.

```totalMiles :: RealFloat a => [(a, a)] -> Int
totalMiles = round . (* 0.621371192) . sum . mapAdjacent dist
```

All that’s left to do is to read in the route and print out the result.

```main :: IO ()
main = either print (print . totalMiles . coords) . fromString .