closest dist point (Tree node) = Just $ second sqrt $ go node (error "closest: current best node uninitialized") (1/0)
    where
        go node best bestDist =
            case node of
                Leaf v a ->
                    let bestDist' = point `dist` v
                    in if bestDist' < bestDist
                       then ((v, a), bestDist')
                       else (best, bestDist)
                Node dim dimValue left right ->
                    let (nearChild, farChild) = if point ! dim < dimValue then (left, right) else (right, left)
                        (best', bestDist') = go nearChild best bestDist
                    in if sqrAxisDistance dim dimValue point < bestDist'
                       then go farChild best' bestDist'
                       else (best', bestDist')
closest dist point (Tree node) = Just $ second sqrt $ go node (error "closest: current best node uninitialized") (1/0)
    where
        go node best bestDist =
            case node of
                Leaf v a ->
                    let bestDist' = point `dist` v
                    in if bestDist' < bestDist
                       then ((v, a), bestDist')
                       else (best, bestDist)
                Node dim dimValue left right ->
                    let (nearChild, farChild) = if point ! dim < dimValue then (left, right) else (right, left)
                        (best', bestDist') = go nearChild best bestDist
                    in if sqrAxisDistance dim dimValue point < bestDist'
                       then go farChild best' bestDist'
                       else (best', bestDist')
closest dist point (Tree node) = Just $ second sqrt $ go node (error "closest: current best node uninitialized") (1/0)
    where
        go node best bestDist =
            case node of
                Leaf v a ->
                    let bestDist' = point `dist` v
                    in if bestDist' < bestDist
                       then ((v, a), bestDist')
                       else (best, bestDist)
                Node dim dimValue left right ->
                    let (nearChild, farChild) = if point ! dim < dimValue then (left, right) else (right, left)
                        (best', bestDist') = go nearChild best bestDist
                    in if sqrAxisDistance dim dimValue point < bestDist'
                       then go farChild best' bestDist'
                       else (best', bestDist')