Took me a bit to appreciate what you just said there, but I see your point now. It&#39;s true, it does have some very nice features. I&#39;m still concerned about creating something which involves too much boilerplate.<div>
<br></div><div>Am I understanding correctly that the URLs will be derived from the names of the datatypes? Also, how would you address URL dispatch in this approach?</div><div><br><div class="gmail_quote">On Tue, Mar 16, 2010 at 8:24 AM, Chris Eidhof <span dir="ltr">&lt;<a href="mailto:chris@eidhof.nl">chris@eidhof.nl</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Creating a number of datatypes (each for every &quot;component&quot;) is interesting because of two things:<br>
<br>
* You can only produce valid URLs (you get that for free)<br>
* You can provide an individual component as a library (e.g. a hackage package)<br>
<br>
I guess that all these approaches can be made equivalent, it&#39;s mostly a matter of style and preference. What I like about my approach is that it&#39;s very light on Template Haskell: the only TH comes from the regular library and is well-tested.<br>

<font color="#888888"><br>
-chris<br>
</font><div><div></div><div class="h5"><br>
On 16 mrt 2010, at 16:16, Michael Snoyman wrote:<br>
<br>
&gt; These approaches will definitely work, but I&#39;m worried that creating a whole set of datatypes to represent URLs is overkill. In Yesod (I&#39;m sure many of you have seen) I use quasi-quoting for defining the resources, like such:<br>

&gt;<br>
&gt; [$mkResources|<br>
&gt; /user:<br>
&gt;     GET: userList<br>
&gt; /user/find/#userid<br>
&gt;     GET: userFind<br>
&gt; /user/name/$username<br>
&gt;     GET: userName<br>
&gt; |]<br>
&gt;<br>
&gt; And so on and so forth. I don&#39;t think defining UserRoute adds much, besides making the job of the library writer a little bit easier by pushing the work off to the user. I think the six lines above succinctly:<br>

&gt;<br>
&gt; * define the valid routes<br>
&gt; * define the data types for arguments<br>
&gt; * define the appropriate mapping to handler functions for each request method<br>
&gt;<br>
&gt; Chris mentioned earlier to me the idea of using quasi-quoting on the link generation side, perhaps like:<br>
&gt;<br>
&gt; [$link|/user/find/6]<br>
&gt;<br>
&gt; I think the only piece of the puzzle missing to combine these two together is to have mkResources output something along the lines of:<br>
&gt;<br>
&gt; data RoutePiece = StaticPiece String | IntPiece | StringPiece<br>
&gt; _validRoutes :: [[RoutePiece]]<br>
&gt; _validRoutes =<br>
&gt;   [ [StaticPiece &quot;user&quot;]<br>
&gt;   , [StaticPiece &quot;user&quot;, StaticPiece &quot;find&quot;, IntPiece]<br>
&gt;   , [StaticPiece &quot;user&quot;, StaticPiece &quot;name&quot;, StringPiece]<br>
&gt;   ]<br>
&gt;<br>
&gt; Now if you write<br>
&gt;<br>
&gt; [$link|/user/find/michael]<br>
&gt;<br>
&gt; link can look up in _validRoutes that there is no matching route and complain at compile time.<br>
&gt;<br>
&gt; Advantages: less typing by the user.<br>
&gt; Disadvantages: we&#39;ll have to restrict the data types allowed, but in practice I think people will usually want only strings and ints anyway. Also, this approach is more complex.<br>
&gt;<br>
&gt; Michael<br>
&gt;<br>
&gt; On Tue, Mar 16, 2010 at 7:04 AM, Chris Eidhof &lt;<a href="mailto:chris@eidhof.nl">chris@eidhof.nl</a>&gt; wrote:<br>
&gt; I have the feeling it adds a lot of complexity. I agree with you that, if you want modularity, your components should only provide relative URLs and need to be parameterized over how to build an absolute URL. I didn&#39;t think of that problem, and using a custom monad transformer is definitely a solution.<br>

&gt;<br>
&gt; However, I&#39;m always hesitant to build up stacks of monad transformers, it adds a lot of complexity. I would rather use something like typeclass, but I&#39;m not sure yet how to do that.<br>
&gt;<br>
&gt; -chris<br>
&gt;<br>
&gt; On 16 mrt 2010, at 14:29, Jeremy Shaw wrote:<br>
&gt;<br>
&gt; &gt; Hello,<br>
&gt; &gt;<br>
&gt; &gt; It looks nearly identical, but without the URLT monad transformer.<br>
&gt; &gt;<br>
&gt; &gt; Instead of ToURL I have the class:<br>
&gt; &gt;<br>
&gt; &gt; class AsURL a where<br>
&gt; &gt;     toURLS :: a -&gt; ShowS<br>
&gt; &gt;     fromURLC :: Consumer String (Failing a)<br>
&gt; &gt;<br>
&gt; &gt; 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:<br>
&gt; &gt;<br>
&gt; &gt; toURL :: (AsURL a) =&gt; a -&gt; String<br>
&gt; &gt; fromURL :: (AsURL a) =&gt; String -&gt; Failing a<br>
&gt; &gt;<br>
&gt; &gt; 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.<br>
&gt; &gt;<br>
&gt; &gt; <a href="http://src.seereason.com/urlt/URLT/TH.hs" target="_blank">http://src.seereason.com/urlt/URLT/TH.hs</a><br>
&gt; &gt;<br>
&gt; &gt; The thing you don&#39;t have is the URLT monad transformer:<br>
&gt; &gt;<br>
&gt; &gt; <a href="http://src.seereason.com/urlt/URLT/Base.hs" target="_blank">http://src.seereason.com/urlt/URLT/Base.hs</a><br>
&gt; &gt;<br>
&gt; &gt; Here is why you want it. Imagine you write an image gallery library:<br>
&gt; &gt;<br>
&gt; &gt; data ImageURL = Upload | ViewImage Int<br>
&gt; &gt;<br>
&gt; &gt; when you call toURL, you are going to get urls like, /Upload, /ViewImage/1, etc.<br>
&gt; &gt;<br>
&gt; &gt; Now let&#39;s say I try to use your library in my application. So at first I try:<br>
&gt; &gt;<br>
&gt; &gt; data MyApp = Upload | FooBar<br>
&gt; &gt;<br>
&gt; &gt; 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 &quot;/Upload&quot; is referring to.<br>

&gt; &gt;<br>
&gt; &gt; So now I try:<br>
&gt; &gt;<br>
&gt; &gt; data MyApp = Upload | FooBar | Images ImageURL<br>
&gt; &gt;<br>
&gt; &gt; now I know that all incoming urls are decoded as MyApp. But there is still a problem. In my code I could write:<br>
&gt; &gt;<br>
&gt; &gt;  toUrl (Images (ViewImage 1))<br>
&gt; &gt;<br>
&gt; &gt; but in your library code, you don&#39;t know anything about the Images constructor. So you just call,<br>
&gt; &gt;<br>
&gt; &gt; toURL (ViewImage 1)<br>
&gt; &gt;<br>
&gt; &gt; which generates /ViewImage/1 instead of the required /Images/ViewImage/1.<br>
&gt; &gt;<br>
&gt; &gt; 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.<br>
&gt; &gt;<br>
&gt; &gt; so in your library you have:<br>
&gt; &gt;<br>
&gt; &gt; image :: ImageURL -&gt; URLT ImageURL m ()<br>
&gt; &gt; image Upload =<br>
&gt; &gt;      do ...<br>
&gt; &gt;           u &lt;- showURL (ViewImage n)<br>
&gt; &gt;           ...<br>
&gt; &gt; image (ViewImage num) = ...<br>
&gt; &gt;<br>
&gt; &gt; Instead of calling toURL, it calls showURL, which adds the context to the URL and then calls toURL on it.<br>
&gt; &gt;<br>
&gt; &gt; And in my code I have:<br>
&gt; &gt;<br>
&gt; &gt; myApp :: MyAPP -&gt; URLT MyApp m ()<br>
&gt; &gt; mpApp Upload = ...<br>
&gt; &gt; myApp FooBar = ...<br>
&gt; &gt; myApp (Images subURL) = nestURL Images $ images subURL<br>
&gt; &gt;<br>
&gt; &gt; the &#39;nextURL Images&#39; adds the Images context to the URLT environment. It can be used to nest multiple levels if needed:<br>
&gt; &gt;<br>
&gt; &gt;  nestURL A $ nestURL B $ nestURL Images $ showURL (ViewImage 1)<br>
&gt; &gt;<br>
&gt; &gt; would get turned into something like:<br>
&gt; &gt;<br>
&gt; &gt;  &quot;/A/B/Images/ViewImage/1&quot;<br>
&gt; &gt;<br>
&gt; &gt; What do you think?<br>
&gt; &gt;<br>
&gt; &gt; - jeremy<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt; On Tue, Mar 16, 2010 at 3:52 AM, Chris Eidhof &lt;<a href="mailto:chris@eidhof.nl">chris@eidhof.nl</a>&gt; wrote:<br>
&gt; &gt; Hey everyone,<br>
&gt; &gt;<br>
&gt; &gt; I just wrote down some of my ideas about type-safe URL handling on github, it&#39;s at <a href="http://gist.github.com/333769" target="_blank">http://gist.github.com/333769</a><br>
&gt; &gt;<br>
&gt; &gt; I think it&#39;s similar to what Jeremy is doing with his urlt package [1].<br>
&gt; &gt;<br>
&gt; &gt; -chris<br>
&gt; &gt;<br>
&gt; &gt; [1]: <a href="http://src.seereason.com/~jeremy/SimpleSite1.html" target="_blank">http://src.seereason.com/~jeremy/SimpleSite1.html</a><br>
&gt; &gt;<br>
&gt; &gt; _______________________________________________<br>
&gt; &gt; web-devel mailing list<br>
&gt; &gt; <a href="mailto:web-devel@haskell.org">web-devel@haskell.org</a><br>
&gt; &gt; <a href="http://www.haskell.org/mailman/listinfo/web-devel" target="_blank">http://www.haskell.org/mailman/listinfo/web-devel</a><br>
&gt; &gt;<br>
&gt;<br>
&gt; _______________________________________________<br>
&gt; web-devel mailing list<br>
&gt; <a href="mailto:web-devel@haskell.org">web-devel@haskell.org</a><br>
&gt; <a href="http://www.haskell.org/mailman/listinfo/web-devel" target="_blank">http://www.haskell.org/mailman/listinfo/web-devel</a><br>
&gt;<br>
<br>
</div></div></blockquote></div><br></div>