Url Parsing in Haskell

Our program will parse a URL, demonstrating how to extract various components from it. Here’s the full source code:

import Network.URI
import Data.Maybe (fromJust)

main :: IO ()
main = do
    -- We'll parse this example URL, which includes a scheme, authentication info, 
    -- host, port, path, query params, and query fragment.
    let s = "postgres://user:pass@host.com:5432/path?k=v#f"

    -- Parse the URL and ensure there are no errors.
    case parseURI s of
        Nothing -> error "Failed to parse URL"
        Just u -> do
            -- Accessing the scheme is straightforward.
            putStrLn $ "Scheme: " ++ uriScheme u

            -- User contains all authentication info
            case uriAuthority u of
                Nothing -> putStrLn "No authority"
                Just auth -> do
                    putStrLn $ "User: " ++ uriUserInfo auth
                    putStrLn $ "Host: " ++ uriRegName auth
                    putStrLn $ "Port: " ++ uriPort auth

            -- Here we extract the path and the fragment after the #.
            putStrLn $ "Path: " ++ uriPath u
            putStrLn $ "Fragment: " ++ fromMaybe "" (uriFragment u)

            -- To get query params in a string of k=v format, use uriQuery.
            putStrLn $ "Query: " ++ uriQuery u

            -- Parsing query params into a map is not provided by Network.URI,
            -- but you could implement this functionality yourself if needed.

To run the program, save it as UrlParsing.hs and use runhaskell:

$ runhaskell UrlParsing.hs
Scheme: postgres:
User: user:pass@
Host: host.com
Port: :5432
Path: /path
Fragment: f
Query: ?k=v

This program demonstrates URL parsing in Haskell:

  1. We use the Network.URI module to parse and manipulate URLs.

  2. The parseURI function is used to parse the URL string into a URI data structure.

  3. We use pattern matching to handle the Maybe result from parseURI.

  4. The URI structure provides fields like uriScheme, uriAuthority, uriPath, uriQuery, and uriFragment to access different parts of the URL.

  5. The uriAuthority field is itself a Maybe type, so we use pattern matching again to safely access its contents.

  6. Unlike the original example, Haskell’s Network.URI doesn’t provide built-in functions to parse query parameters into a map. You would need to implement this functionality yourself if required.

  7. Haskell’s strong type system ensures that we handle all possible cases (like when a URL component is missing) explicitly, leading to more robust code.

This example showcases Haskell’s pattern matching, Maybe types for handling potential absence of data, and its approach to parsing structured data like URLs.