
On Sun, Sep 23, 2012 at 7:02 AM, Michael Snoyman
On Sun, Sep 23, 2012 at 11:14 AM, Sebastian Fischer
wrote:
The most basic reason is because I think multiple syntaxes is a good thing. Embedding a URL is inherently a different activity than embedding a piece of text, and I'd like the code to reflect that. In Hamlet, the following is clear:
<a href=@{foo}>#{bar}
I know that foo is a URL value, and bar is not. If I accidentally included the wrong type for `foo`, Hamlet can catch it.
But that doesn't prevent you from making these mistakes, right? <a href=#{bar}> <a class=@{foo}> It seems like we could achieve a similar effect in HSP by using a newtype wrapper? newtype At url = At url And then having our EmbedAsAttr look like:
instance (XMLGenerator m, MonadRoute m, URL m ~ url) => EmbedAsAttr m (Attr key (At url)) where
So that you now have to write: home</a> And the following would be rejected: <a href=Home>home</a> not a url</a> <a><% Home %></a> <a><% (At Home) %></a> Though, the following would still be accepted: oops</a> <a href=NotAURL>
I actually contacted Jeremy off list about this issue to get a better understanding of how HXT works, and it seems to me that it's pushing a lot of the infrastructure into a monad with typeclass instances. I don't know all the details, so I can't really speak to that approach. But I *can* speak to how Hamlet was designed, and I think the fact that context is irrelevant is very powerful. Each Hamlet template is passed a URL rendering function, which ensures automatically that all embedded URLs are of the correct type.
This is especially useful for cases such as subsites. Suppose that you have a subsite for static files, and you want to give a user a link to an image. You could construct such a static route along the lines of:
StaticRoute ["myimage.png"]
(Yesod users will probably recognize that these links are automatically generated, so you could just use the `myimage_png` identifier, which ensures you do not have any typos.)
The question is: what does `myimage_png` render to? And the answer depends entirely on your application. There are a number of possibilities:
1. You stuck your static subsite at the "standard" location of /static, so it renders to /static/myimage_png 2. You used a nonstandard location: /foo 3. You don't even have a static subsite set up 4. You have multiple static subsites set up
In any event, trying to use `<img src=@{myimage_png}>` will fail in *all* of these cases with a message along the lines of "Route Static does not match Route App" which, if you're familiar with GHC error messages, means that you tried to use a route for the static subsite when you should have used a route for the application. The only way to create the link is to wrap up `myimage_png` in the appropriate constructor, which in common nomenclature would work out to `
`.
If I understand you correctly, you have a type like:
data Static = StaticRoute [FilePath]
And also a route like:
data App = StaticR StaticRoute
And you are saying that you can not do:
in a template that requires
the App route? you instead need:
?
That would be exactly the same as HSP. Assuming we have something like:
type MyApp url a = ...
if you have:
foo :: MyApp App XML
foo = my image</a>
It would fail. You would need:
foo :: MyApp App XML
foo = my image</a>
If you already had a template like:
foo :: MyApp Static XML
foo = my image</a>
and you want to use it in 'MyApp App XML' template, you should be able
to wrap it in StaticR using: 'nestURL StaticR'
In Hamlet you explicitly pass in a url rendering function. In the
HSP+web-routes stuff we also pass in a url rendering function. The
primary difference, I think, is that in hamlet it is an explicit
argument to the template and in HSP+web-routes we put the render
function in a ReaderT monad?
- jeremy