Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to denote a static Haskell URI in code with Network.URI?

Tags:

uri

haskell

In the Haskell package Network.URI there is the parseURI :: String -> Maybe URI function.

I'd like to have a couple of static URIs in my code. Is it reasonable to write the following?

Just myURI = parseURI "http://google.com/"

The "problem" with this is that if the URI string is actually malformed, it is only caught at runtime with a pattern failed exception.

I'd like to avoid the tedium of constructing the URI datatype directly (which breaks apart the URI and makes it lose its conceptual meaning somewhat).

Is there a better way to have the static URI in code and be more "safe"?

like image 823
Ana Avatar asked May 20 '15 23:05

Ana


2 Answers

How about using Template Haskell to validate a static URL using isURI at compile time? It's safe to use fromJust at runtime now that the URL must be valid.

For example, define staticURI like this.

{-# LANGUAGE TemplateHaskell #-}

module URI where

import Data.Maybe (fromJust)
import Network.URI (URI, isURI, parseURI)
import Language.Haskell.TH (Q, TExp)

staticURI :: String -> Q (TExp URI)
staticURI uri | isURI uri = [|| fromJust $ parseURI uri ||]
              | otherwise = fail $ "Invalid URI: " ++ uri

Then, you can define your URL in other modules like this.

{-# LANGUAGE TemplateHaskell #-}

import Network.URI (URI)
import URI (staticURI)

url :: URI
url = $$(staticURI "http://www.google.com/")

badUrl :: URI
badUrl = $$(staticURI "http://www.google.com/##")

When you pass a malformed URL to staticURI, a compiler will emit an error.

Invalid URI: http://www.google.com/##
In the Template Haskell splice
  $$(staticURI "http://www.google.com/##")
In the expression: $$(staticURI "http://www.google.com/##")
In an equation for ‘url’:
    url = $$(staticURI "http://www.google.com/##")
like image 166
snak Avatar answered Nov 06 '22 19:11

snak


Is it reasonable to write the following?

No, don't pattern match with Just unless you are sure that your URI isn't malformed. A URI like this will give Nothing leading to runtime error:

λ> parseURI "http:/\\/google.com/"
Nothing

Instead, just represent the URI in Maybe type and do your computations on that using functions like fmap and others. One another way would be to check if it contains a valid URI using the function isURI or any of the other appropriate functions defined in Network.URI and then handle the appropriate cases:

λ> isURI "http:/\\/google.com/"
False
λ> isURI "http://google.com"
True
like image 22
Sibi Avatar answered Nov 06 '22 19:11

Sibi