closestDry
- бесполезный беспорядок, так что избавьтесь от него. Затем напишем функцию distanceTo
, которая дает вам расстояние от координат до места:
distanceTo :: Float -> Float -> Place -> Float
distanceTo lat lon place = distance lat lon (north place) (east place)
Теперь давайте напишем функцию, которая связывает места с расстояниями до них:
distancesTo :: Float -> Float -> [Place] -> [(Place, Float)]
distancesTo lat lon = map (\place -> (place, distanceTo lat lon place))
Попробуем:
λ> distancesTo 51.5 (-0.1) testData
[(Place {name = "London", north = 51.5, east = -0.1, rainfall = [0,0,5,8,8,0,0]},0.0),(Place {name = "Norwich", north = 52.6, east = 1.3, rainfall = [0,6,5,0,0,0,3]},1.7804484),(Place {name = "Birmingham", north = 52.5, east = -1.9, rainfall = [0,2,10,7,8,2,2]},2.059126),(Place {name = "Hull", north = 53.8, east = -0.3, rainfall = [0,6,5,0,0,0,4]},2.3086786),(Place {name = "Newcastle", north = 55.0, east = -1.6, rainfall = [0,0,8,3,6,7,5]},3.8078866),(Place {name = "Aberdeen", north = 57.1, east = -2.1, rainfall = [0,0,6,5,8,2,0]},5.946426),(Place {name = "St Helier", north = 49.2, east = -2.1, rainfall = [0,0,0,0,6,10,0]},3.0479496)]
Выглядит хорошо!
Теперь мы можем использовать minimumBy
, comparing
и snd
, чтобы получить кортеж, и затем извлеките только место с помощью fst
:
import Data.Foldable (minimumBy)
import Data.Ord (comparing)
closestTo :: Float -> Float -> [Place] -> Place
closestTo lat lon places = fst $ minimumBy (comparing snd) (distancesTo lat lon places)
Давайте попробуем:
λ> closestTo 51.5 (-0.1) testData
Place {name = "London", north = 51.5, east = -0.1, rainfall = [0,0,5,8,8,0,0]}
Успех!
Как альтернатива distancesTo
, вы также можете рассчитать расстояния с помощью comparing
, например:
closestTo :: Float -> Float -> [Place] -> Place
closestTo lat lon places = minimumBy (comparing (distanceTo lat lon)) places
Преимущество этого состоит в том, что вам не нужен ни один из кортежей, а в том, что вы пересчитываете расстояние для одного и того же места несколько раз. .
Предупреждение в любом случае: minimumBy
- опасная частичная функция, которая взломает sh вашу программу, если она когда-либо получит пустой список, что произойдет, если closestTo
получит пустой list:
λ> closestTo 51.5 (-0.1) []
*** Exception: Prelude.foldl1: empty list
Если вы заботитесь об этом, вам нужно избежать этого, возвращая Maybe Place
вместо этого и корректируя код так, чтобы он возвращал Nothing
, когда список ввода пуст, вместо вызова minimumBy
. (IMO, это бородавка в Haskell, и minimumBy
должен просто вернуть Maybe
вместо того, чтобы взломать sh.)