
On Wed, Feb 16, 2011 at 5:02 PM, Dmitry Kurochkin
On Wed, 16 Feb 2011 12:42:26 +0200, Michael Snoyman
wrote: On Wed, Feb 16, 2011 at 12:37 PM, Dmitry Kurochkin
wrote: On Wed, 16 Feb 2011 12:02:34 +0200, Michael Snoyman
wrote: On Wed, Feb 16, 2011 at 11:49 AM, Dmitry Kurochkin
wrote: On Wed, 16 Feb 2011 06:25:54 +0200, Michael Snoyman
wrote: It looks good. Instead of the mkSize TH function, if you just define an IsString instance, then anyone using OverloadedStrings will be able to use string literals. I haven't confirmed this yet, but it might even be possible to embed those string literals inside Cassius and GHC will still apply fromString appropriately.
I was thinking about it. But as I understand, it would not work unless you explicitly specify the resulting size type. E.g.
let s = fromString "100px"
How would GHC know that in this case fromString for PixelSize should be used? This would force you to add explicit (s :: PixelSize) type. This is something I want to avoid: Type should be determined from string constant. Or am I missing something?
No, you're right, TH is the way to go here.
How is it better to integrate to Hamlet? I guess MkSizeType should go to Text/Hamlet/ directory and Size.hs will be part of Text/Cassius.hs.
That sounds fine, frankly it doesn't matter to me where MkSizeType goes since it won't be an exposed module (right?). And Size.hs's code would go in Text.Cassius, correct.
Yeah, MkSizeType module is not exported.
Patch for Hamlet attached.
As far as variables inside templates: I personally think that's crossing the line again into stuff templates shouldn't be dealing with, but I'm open for discussions. Since templates tie in so well with Haskell, I just don't think it's worth adding a whole bunch of extra code and syntax to make it work.
I understand this is a feature which may be used inappropriately. But here is mine justification for it:
Consider you want to write a simple Cassius template:
#a height: 100px #b width: 100px
#a and #b are related and their width and height should be always the same. So it makes perfect sense to define (commonSize = $(mkSize "100px")) and use it instead of literals. I know that commonSize is needed and used only for that Cassius template, but I have to define it in an external Haskell module. That makes template not self-contained and harder to read, pollutes Haskell code with declarations that should be local to a template. IMO this cases illustrates how local template variables may be the right solution:
#{let commonSize = $(mkSize "100px")} #a height: #{commonSize} #b width: #{commonSize}
Actually, I think this code snippet proves the opposite point. It's not really possible to embed TH in a template. I think adding in a whole bunch of Haskell features to Cassius (et al) will simply start people wishing they *were* programming in Haskell instead of templates. My opinion: keep the templates simple and to the point, put the logic in Haskell where you have more power.
Sigh. It is possible to use TH in QQ, hence I thought it is possible to use it in Hamlet as well.
A QQ block is just a String that needs to be interpreted by a Haskell function into a "Q Exp". Each and every added feature needs to be coded from scratch, and as such, will never be done as well as features included in Haskell itself. That's a large part of my reluctance to adding everything and the kitchen sink (besides the fact that I think it's not a good idea for a templating language anyway).
Thanks for explanation. I think I am convinced for now :)
Regards, Dmitry
Michael
Thanks, patch applied. I'd like to look at this just a little bit more before releasing to Hackage, but it looks like a nice addition. Thank you! Michael