I’ve given it a fair try, but I must say that what appears to be the standard way of writing HTML in Haskell-like languages and frameworks (Yesod, Elm, Halogen…) doesn’t quite compute to me. I can imagine that I’m not the only one having a hard time processing that this:
The latter is universally readable and there’s a clear visual distinction between properties and contents (meaning that in the glimpse of an eye, one can understand whether something is a property value like btn-primary, or some content like Submit or even another nested tag).
The former is, at least to the untrained eye, quite cryptic, and more importantly there is absolutely no visual distinction between properties and content, both being enclosed in square brackets, which to me sounds like a net negative (and a massive one) compared to the regular HTML version.
Is there any alternative eDSL in PureScript that would either match more closely the natural HTML syntax (like JSX does for JavaScript), or at least would provide clear visual distinction between properties and contents?
EDIT
I stumbled across Smolder which does a better job at distinguishing between properties/content but it doesn’t seem to be maintained anymore (last commit from more than almost two years ago).
I think it’s mostly a matter of habbit. But to me, the former way is more appropriate and appealing than the latter. It’s all not just about “the glimpse of an eye”, but the correctness and overal simplicity.
one can understand whether something is a property value like btn-primary , or some content like Submit or even another nested tag
You could make an eDSL like so, but when you get it wrong the errors would be horrible:
import Unsafe.Coerce
foreign import data Boolean :: Type
foreign import data True :: Boolean
foreign import data False :: Boolean
foreign import data Nat :: Type
foreign import data Zero :: Nat
foreign import data Succ :: Nat -> Nat
data OpenEl = OpenEl
data CloseEl = CloseEl
foreign import data HTML :: Type
class Next :: Nat -> Boolean -> Type -> Type -> Constraint
class Next n attr i o | i n -> o
instance a ::
( Next (Succ n) False i o
) => Next (Succ n) True (Record r) (i -> o)
instance b ::
( Next (Succ n) False i o
) => Next (Succ n) attr String (i -> o)
instance c ::
( Next (Succ n) True i o
) => Next n attr OpenEl (String -> i -> o)
instance d :: Next (Succ Zero) attr CloseEl HTML
instance e ::
( Next (Succ n) False i o
) => Next (Succ (Succ n)) attr CloseEl (i -> o)
-- you'd actually implement a member for each of the instances, but it's not important here
-- so we use unsafeCoerce
parse :: forall i o. Next Zero False i o => i -> o
parse = unsafeCoerce unit
test = parse
OpenEl "div"
OpenEl "div" { attr: "Hello" }
"Hello"
OpenEl "button" CloseEl
"World!"
CloseEl
CloseEl
The verbosity of OpenEl/CloseEl can be improved but it keeps the implementation here short
To be honest, this doesn’t really solve the original issue of it being easier to read, as I think in an actual implementation it wouldn’t use a record for the attributes? It’s mostly just a case of formatting attributes on the same line
Actually I’m guessing the latter example just above might not be too hard to implement on top of HalogenHTML, and (to me at least) it would already look much more readable.
Eventually for a real-life project you probably still will end up with some kind of custom DSL that serves the project’s needs and personal preferences.
For example to have your custom text input widget you just make functions like that: