import Control.Monad (join)
import Data.Bifunctor (bimap)
import Text.Printf (printf)




haversine :: Float -> Float
haversine = (^ 2) . sin . (/ 2)




greatCircleDistance ::
  (Float, Float) ->
  (Float, Float) ->
  Float
greatCircleDistance = distDeg 6371
  where
    distDeg radius p1 p2 =
      distRad
        radius
        (deg2rad p1)
        (deg2rad p2)
    distRad radius (lat1, lng1) (lat2, lng2) =
      (2 * radius)
        * asin
          ( min
              1.0
              ( sqrt $
                  haversine (lat2 - lat1)
                    + ( (cos lat1 * cos lat2)
                          * haversine (lng2 - lng1)
                      )
              )
          )
    deg2rad = join bimap ((/ 180) . (pi *))


main :: IO ()
main =
  printf
    "The distance between BNA and LAX is about%0.f km.\n"
    (greatCircleDistance bna lax)
  where
    bna = (36.12, -86.67)
    lax = (33.94, -118.40)