Programming Praxis – Weather Forecast

In today’s Programming Praxis exercise our task is to print the weather forecast for a given city in the United States. Let’s get started, shall we?

The Scheme solution uses wget to download the file first. In Haskell, however, we can just use a library for this purpose.

import Network.HTTP

Thanks to the library, the actual function is trivial: download the file and print either the error message if it can’t be found or the weather forecast if it can.

showWeather :: String -> String -> IO ()
showWeather state city = either print (putStrLn . rspBody) =<<
    simpleHTTP (getRequest $ "http://weather.noaa.gov/pub/data/\
        \forecasts/city/" ++ state ++ "/" ++ city ++ ".txt")

A quick to see if everything works correctly:

main :: IO ()
main = showWeather "mo" "st_louis"

Not very warm at 47 degrees Fahrenheit, but at least it’s dry.

About these ads

Tags: , , , , , , ,

4 Responses to “Programming Praxis – Weather Forecast”

  1. xbonez Says:

    Nice solution, short and simple. However, the question states to get the weather forecast ‘for a requested city’. I’m not sure they mean what I think they mean, but just for the sake of challenge, could you retrieve the weather forecast without knowing the state? You’d have to iterate through all the state subfolders.

  2. xbonez Says:

    PS – to that effect, I wrote a method in C# that would get a list of all the states from the directory itself. I’m quite sure this is an extremely sloppy and inefficient implementation, though:

    private static List GetStates(string url)
    {
    string result=String.Empty;
    try
    {
    WebClient client = new WebClient();
    result = client.DownloadString(url);
    }
    catch (Exception ex)
    {
    Console.WriteLine(ex.ToString());
    return null;
    }

    string[] split = result.Split(‘\n’);

    string identifier = ” <a href=\"";
    List states = new List();

    for (int i = 0; i < split.Length; i++)
    {
    if (split[i].StartsWith(identifier))
    {
    split[i] = split[i].Substring(identifier.Length, 2);
    states.Add(split[i]);
    }
    }

    return states;
    }

  3. xbonez Says:

    In the above code fragment, the argument passed in is :

    http://weather.noaa.gov/pub/data/forecasts/city/

  4. Remco Niemeijer Says:

    Here’s what I came up with:

    import Network.HTTP
    import Text.Regex.Posix
    
    get :: String -> IO String
    get = fmap (either show rspBody) . simpleHTTP . getRequest
    
    showWeather :: String -> IO ()
    showWeather city = do
        let base = "http://weather.noaa.gov/pub/data/forecasts/city/"
        states <- fmap (map last . (=~ "href=\"(../)\"")) $ get base
        cities <- fmap (zip states) $ mapM (get . (base ++)) states
        let state = fst . head $ filter ((=~ city) . snd) cities
        putStrLn =<< get (base ++ state ++ city ++ ".txt")
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

Join 35 other followers

%d bloggers like this: