<br><br><div class="gmail_quote">On Tue, Mar 16, 2010 at 3:00 PM, Jeremy Shaw <span dir="ltr">&lt;<a href="mailto:jeremy@n-heptane.com">jeremy@n-heptane.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On Tue, Mar 16, 2010 at 11:54 AM, Chris Eidhof <span dir="ltr">&lt;<a href="mailto:chris@eidhof.nl" target="_blank">chris@eidhof.nl</a>&gt;</span> wrote:<br></div><div class="gmail_quote"><div class="im"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div>On 16 mrt 2010, at 16:46, Michael Snoyman wrote:<br>
<br>
&gt; 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.<br>


<br>
</div>Yes. Generic programming (which is what the regular library provides) tries to hide the boilerplate (Template Haskell) code in a library and provides you with combinators so that you can program on the structure of a datatype. This is also at the core of my regular-web library [1], which generates forms/html/json/xml in the same way. You notice that on lines 34-36, I use the exact same TH calls. Once you did that, you get HTML and Formlets generation for free!</blockquote>

<div><br></div></div><div>Using <a href="http://URLT.TH" target="_blank">URLT.TH</a> you would just need the one-liner:</div><div><br></div><div>$(deriveAsURL &#39;&#39;UserRoute)</div><div><br></div><div>However, if that is asking too much, I have also added URLT.Regular:</div>

<div><br></div><div><a href="http://src.seereason.com/urlt/URLT/Regular.hs" target="_blank">http://src.seereason.com/urlt/URLT/Regular.hs</a></div><div><br></div><div>So instead you do:</div><div><br></div><div><div>$(deriveAll &#39;&#39;UserRoute &quot;PFUserRoute&quot;)</div>

<div>type instance PF UserRoute = PFUserRoute</div><div><br></div><div>instance AsURL UserRoute where</div><div>  toURLS   = gtoURLS . from</div><div>  fromURLC = fmap (fmap to) gfromURLC</div></div><div class="im"><div>
 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>&gt; Am I understanding correctly that the URLs will be derived from the names of the datatypes?<br>
<br>
</div>Exactly!</blockquote><div><br></div></div><div>URLT currently allows you to generate the urls from the names via template haskell, generics, or by writing instances by hand. I would like to add support for QuasiQuotes similar to what is done in Yesod. </div>
<div class="im">
<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
&gt; Also, how would you address URL dispatch in this approach?<br>
<br>
</div>A URL is represented by a datastructure, e.g. ApplicationRoute. You would write a function &quot;dispatch :: ApplicationRoute -&gt; Application&quot;. Dispatch is not part of the library (and it shouldn&#39;t be, imo). In the module &quot;MyApp.UserController&quot; you might write a function &quot;dispatchUser :: UserRoute -&gt; Application&quot;, which is called by the original dispatch function.<br>

<br></blockquote><div><br></div></div><div>That is how URLT works -- except better. Your function type will be like:</div><div><br></div><div>dispatchApp :: (ShowURL m, URL m ~  ApplicationRoute) =&gt; ApplicationRoute -&gt; m a</div>

<div><br></div><div>MyApp.UserController might have a function like:</div><div><br></div><div>dispatchUser  :: (ShowURL m, URL m ~ UserRoute) =&gt; UserRoute -&gt; m a</div><div><br></div><div>the top level dispatchApp would call it like:</div>

<div><br></div><div>dispatchApp (User userURL) = nestURL User $ dispatchApp userURL</div><div><br></div><div><div><br>The constraints ensure that your app is also only generating URLs of type ApplicationRoute. If your app was generating urls of type UserRoute, but expecting incoming urls of type ApplicationRoute, that clearly would not work.</div>

<div><br></div><div>Imagine if you accidentally wrote:</div><div><br></div><div>dispatchApp Login =</div><div>         do let url = toURL List</div><div>              in &lt;a href=list&gt;list&lt;/a&gt;</div><div><br></div>

<div>Here, in the dispatchApp function I accidentally called &#39;toURL List&#39; instead of, &#39;toURL (User List)&#39;. In your code that is *not* caught as a type error. With the ShowURL monad it is caught as a compile time error. If the goal is type-safe URLs I think it is essential to catch this error, don&#39;t you?</div>

</div><div><br></div><font color="#888888"><div> - jeremy</div></font></div>
</blockquote></div><br><div>Firstly, I haven&#39;t read through all of URLT, so take anything I say with a grain of salt. I&#39;ll happily be corrected where I misspeak.</div><div><br></div><div>I&#39;m not sure if I really see the big advantages for URLT over the code that I posted. As an advantage to my code, it&#39;s *much* smaller and easier to digest. I understand the URLT is doing a lot of other stuff with TH and the like, but I&#39;m trying to look at the core of URL dispatch here. I would imagine having a system like this:</div>
<div><br></div><div>* An underlying typeclass/datatype/whatever for defining a set of URLs. For lack of a better term, let&#39;s call it a WebSubapp.</div><div>* The ability to embed a WebSubapp within another WebSubapp.</div>
<div>* The ability to convert a resource in a WebSubapp into a relative path, and vice-versa.</div><div>* Dispatch a request to a specific resource, passing also (either via explicit argument or through a Reader monad) a function to convert a resource into an absolute path.</div>
<div>* Convert a WebSubapp into an Application. I&#39;ll assume for the moment that would be a Network.Wai.Application.</div><div><br></div><div>Once we had that skeleton, we could dress it up however we want. For Yesod, I would change the mkResources quasi-quoter to produce an instance of WebSubapp. Others may wish to use the regular package, some might use TH, and others still may code it all directly.</div>
<div><br></div><div>However, if we keep the same skeleton, then all of these will operate with each other seemlessly.</div><div><br></div><div>The one piece of the puzzle that still irks me just a bit is initialization, such as creating database connections, loading settings, etc. I have some ideas on that as well, but I&#39;ll wait to discuss them after we get some of the more basic components addressed.</div>
<div><br></div><div>Michael</div>