class AsURL a where
toURLS :: a -> ShowS
fromURLC :: Consumer String (Failing a)
With is basically the same. Except toURLS returns a ShowS instead of [String]. fromURLC consumes a list of [String]. These functions are wrapped up to provide:
toURL :: (AsURL a) => a -> String
fromURL :: (AsURL a) => String -> Failing a
I do not have generics based url printing/parsing, but there is no reason it could not be added. I do have template haskell based code though.
The thing you don't have is the URLT monad transformer:
Here is why you want it. Imagine you write an image gallery library:
data ImageURL = Upload | ViewImage Int
when you call toURL, you are going to get urls like, /Upload, /ViewImage/1, etc.
Now let's say I try to use your library in my application. So at first I try:
data MyApp = Upload | FooBar
But when a URL comes in, how do I know if I should decode it as MyApp or ImageURL? Do I try both and see which one succeeds? Except we both have a constructor Upload, so both will succeed. There is no way to tell with Upload the path "/Upload" is referring to.
So now I try:
data MyApp = Upload | FooBar | Images ImageURL
now I know that all incoming urls are decoded as MyApp. But there is still a problem. In my code I could write:
toUrl (Images (ViewImage 1))
but in your library code, you don't know anything about the Images constructor. So you just call,
toURL (ViewImage 1)
which generates /ViewImage/1 instead of the required /Images/ViewImage/1.
What I need is someway to tell your library code what prefix to add at the beginning. That is exactly what the URLT monad does. It just holds a function that adds a prefix to the URL.
so in your library you have:
image :: ImageURL -> URLT ImageURL m ()
image Upload =
do ...
u <- showURL (ViewImage n)
...
image (ViewImage num) = ...
Instead of calling toURL, it calls showURL, which adds the context to the URL and then calls toURL on it.
And in my code I have:
myApp :: MyAPP -> URLT MyApp m ()
mpApp Upload = ...
myApp FooBar = ...
myApp (Images subURL) = nestURL Images $ images subURL
the 'nextURL Images' adds the Images context to the URLT environment. It can be used to nest multiple levels if needed:
nestURL A $ nestURL B $ nestURL Images $ showURL (ViewImage 1)
would get turned into something like:
"/A/B/Images/ViewImage/1"
What do you think?
- jeremy