blaze-html icon indicating copy to clipboard operation
blaze-html copied to clipboard

How to avoid toValue and toHtml?

Open johannesgerer opened this issue 11 years ago • 7 comments

How can I avaoid having to use toValue/toHtml so often. It comes up basically in any template, that has parameters. As an example take:

myLink url name = a ! href (toValue url) $ toHtml $ name

What do you think about providingth following dashed version of the tags (either manually or with e.g. Template Haskell):

href' :: ToValue a => a -> Attribute
href' = href . toValue

a' :: ToMarkup a => a -> Html
a' = a . toHtml

They even work with literate strings, if OverloadedString is swithed off (as String is in ToMarkup and ToValue).

What do you think about that? Should I send a pull request?

johannesgerer avatar Jun 11 '14 21:06 johannesgerer

I implemented the following TH code that does the job for me and is type-safe:

{-# LANGUAGE TemplateHaskell #-}
module BlazeTH where

import           Language.Haskell.TH
import           Language.Haskell.TH.Lib
import           Text.Blaze
import           Text.Blaze.Internal

dash :: Q Exp -> Q Type -> [Name] -> Q [Dec]
dash f t = mapM $ \n -> funD (mkName $ nameBase n ++ "'")
                        [clause [varP x] (normalB
                        [| $(varE n) $ $f $(varE x) :: $t |]) []]
  where x = mkName "x"


dashAttr = dash [|toValue|] [t|Attribute|]
dashTag = dash [|toMarkup|] [t|Markup|]

Usage

dashAttr ['href,'A.id,'A.style]
dashTag ['a,'b,'h1]

myLink url name = a' ! href' url $ name

This solution needs #89

johannesgerer avatar Jun 12 '14 00:06 johannesgerer

I'm not sure if avoiding using toHtml/toValue is a good purpose on its own. I think it's similar to using fromIntegral a lot if you're doing calculations, or toJSON when you're constructing Aeson objects.

jaspervdj avatar Jun 12 '14 09:06 jaspervdj

For me using toHtml/toValue feels different from the others. It feels like boilerplate, which has to be written everytime I use href. Plus, I do not see such an easy way to get rid of fromIntegral or toJSON.

EDIT: Aeson actually puts toJSON into encode, so users to not need to put it in front of every encode call. The type encode :: ToJSON a => a -> ByteString makes sense and I think href :: ToValue a => a -> Attribute would make sense.

johannesgerer avatar Jun 12 '14 09:06 johannesgerer

I was surprised by this just now, playing with Blaze for the first time. It felt like boilerplate to me too, as I thought Blaze would be merrily converting my types to attributes as appropriate, like with the literal String.

Specifically I wanted to see how web-routes would integrate with Blaze, and thought I would just throw a route in the Blaze e.g. a ! href Foo $ "Foo me!", then create a relevant Blaze instance for my AppUrl. At that point I looked at the docs and learned otherwise.

simon-nicholls avatar Oct 03 '14 10:10 simon-nicholls

There is an easy way to get rid of it in your templates. Just define your own combinator, e.g., appHref that combines your conversion and the use of href. This works best if you import blaze-html qualified. The key benefit is that blaze-html remains decoupled from the different application scenarios and doesn't have to make opinionated choices. Am 03.10.2014 12:45 schrieb "Si" [email protected]:

I was surprised by this just now, playing with Blaze for the first time. It felt like boilerplate to me too, as I thought Blaze would be merrily converting my types to attributes as appropriate, like with the literal String.

Specifically I wanted to see how web-routes would integrate with Blaze, and thought I would just throw a route in the Blaze e.g. a ! href Foo $ "Foo me!", then create a relevant Blaze instance for my AppUrl. At that point I looked at the docs and learned otherwise.

— Reply to this email directly or view it on GitHub https://github.com/jaspervdj/blaze-html/issues/88#issuecomment-57779639.

meiersi avatar Oct 03 '14 11:10 meiersi

johannesgerer already shows my prior expectations in a technical way. I figured href would have the type signature that he details for href'. Why should String have all the easy living fun?

It seemed natural that AttributeValue conversions are represented by toValue implementations, so I'd look to do that in a workaround module. But that module wouldn't be application specific, only my ToValue instances would be, and it raises the question as to why not provide this in Blaze itself.

So I was throwing in a solidarity comment. Now that I know to use toValue and toHtml, then sure, I'd like to save some typing now. Perhaps I'll even grow to love those twins of typing. But to me as a first time user, my toX-less blaze already looked sweet (expressing everything necessary); it's this user experience that I wished to (overly by now) convey.

simon-nicholls avatar Oct 03 '14 17:10 simon-nicholls

The problem with attribute values is that they have wildly differing structures and acceptable values. AttributeValue doesn't capture that complexity in its type. This makes toValue into a dangerous sledge hammer, like unsafePerformIO: it's fine to use the function if you know what you're doing; but if you misuse the function, then you'll end up constructing invalid output and the type system cannot help you catch those errors. For this reason, toValue has to be explicit, because its use implies a proof-obligation. The compiler cannot prove or disprove its correctness; the programmer has to do that. Thus, the compiler cannot add toValues implicitly, because it has no way of knowing which cases are correct and which ones are not.

peti avatar May 07 '15 13:05 peti