-- Helper function to map over the error case (Left) mapLeft :: (e -> e') -> Either e a -> Either e' a mapLeft f (Left e) = Left (f e) mapLeft _ (Right a) = Right a -- Define placeholder types newtype Location = Location Int deriving Show newtype LocationError = LocationError String deriving Show newtype Weather = Weather String deriving Show newtype WeatherError = WeatherError String deriving Show newtype Conditions = Conditions String deriving Show newtype ConditionsError = ConditionsError String deriving Show -- Mock functions getLocation :: String -> Either LocationError Location getLocation _ = Right (Location 1) -- Example success getWeather :: Location -> Either WeatherError Weather getWeather _ = Right (Weather "Sunny") -- Example success toConditions :: Weather -> Either ConditionsError Conditions toConditions _ = Right (Conditions "Clear Sky") -- Example success -- Main logic using do notation printConditionsAt :: String -> IO () printConditionsAt locationId = do let result = do location <- mapLeft (\e -> "Could not get location by ID: " ++ show e) $ getLocation locationId weather <- mapLeft (\e -> "Could not get the weather at location " ++ show location ++ ": " ++ show e) $ getWeather location conditions <- mapLeft (\e -> "Could not convert weather to conditions: " ++ show e) $ toConditions weather return $ "Weather at " ++ show location ++ ": " ++ show weather ++ " - " ++ show conditions case result of Left err -> putStrLn err Right msg -> putStrLn msg -- The entry point that was missing main :: IO () main = printConditionsAt "123"