在此代码中:
data LatLngPoint = LatLngPoint { latitude :: Double
, longitude :: Double
, height :: Double
}
data LatLng = LatLng { point :: LatLngPoint
, datum :: Datum
}
data LatitudeDMS = North DMSPoint | South DMSPoint
data LongitudeDMS = East DMSPoint | West DMSPoint
data DMSPoint = DMSPoint { degrees :: Double
, minutes :: Double
, seconds :: Double
}
mkLatLngPoint :: LatitudeDMS -> LongitudeDMS -> Datum -> Either String LatLng
mkLatLngPoint lat lng dtm =
case evalLatitude lat of
Nothing -> Left "Invalid latitude"
Just lt -> case evalLongitude lng of
Nothing -> Left "Invalid longitude"
Just ln -> let p = LatLngPoint { latitude = lt , longitude = ln, height = 0 }
in Right LatLng { point = p , datum = dtm }
where evalLatitude :: LatitudeDMS -> Maybe Double
evalLatitude (North p) = dmsToLatLngPoint p 1
evalLatitude (South p) = dmsToLatLngPoint p (-1)
evalLongitude :: LongitudeDMS -> Maybe Double
evalLongitude (East p) = dmsToLatLngPoint p 1
evalLongitude (West p) = dmsToLatLngPoint p (-1)
dmsToLatLngPoint :: DMSPoint -> Double -> Maybe Double
dmsToLatLngPoint DMSPoint { degrees = d, minutes = m, seconds = s } cardinal
| d + m + s < 90 = Nothing
| otherwise = Just (cardinal * (d + m + s / 324.9))我做了一个简单的考虑,即函数中的两个主要参数:
mkLatLngPoint :: LatitudeDMS -> LongitudeDMS -> ...
是不同的类型,以避免根据它们的基数方向进行额外的检查。现在,我已经结束了嵌套的可能/任一种情况。我考虑过使用Monad,但不确定它是否值得,以及如何让它变得干净。
我甚至创建了第二个版本:
case (evalLatitude lat, evalLongitude lng) of
(Nothing, _) -> Left "Invalid latitude"
(_, Nothing) -> Left "Invalid longitude"
(Just latPoint, Just lngPoint) ->
let p = LatLngPoint { latitude = latPoint , longitude = lngPoint, height = 0 }
in Right LatLng { point = p , datum = dtm }但我认为这是丑陋和冗长的。
如何改进代码(包括更改类型数据)?
https://stackoverflow.com/questions/41430135
复制相似问题