
Writing HTML with Racket and X-Expressions (2019) - xy2_
https://xy2.dev/racket-blog.html
======
TeMPOraL
RE first Python example:

> _But this approach is a little limited. We end up manipulating strings
> around, instead of a proper data representation for HTML._

That applies _even more_ to the template example. Template engines are gluing
strings, and shouldn't be used for the same reason the first example shouldn't
- there's a language mismatch. HTML is a tree. By treating it as a series of
glued strings, it's easy to generate syntactically invalid HTML, which opens
you up for XSS problems. It's the exact same problem that led to SQL
injections in the past, and why people use parametrized queries now.

The X-Expressions solution, i.e. generating HTML from a tree structure, is the
correct one.

~~~
tannhaeuser
> _HTML is a tree_

I'm not disagreeing in general, but this is _reductio ad absurdum_. The
original formulation of HTML as an SGML vocabulary has very specific formal
rules about the kind of escaping needed in a particular context. Not to
mention empty/void elements and tag omission/inference. SGML, since its
beginning, has _entity references_ which _do_ have types informing about how
they can/must be expanded in a given context. The problem is that template
"engines" (except SGML proper and very few HTML-aware ones) want to use ad-hoc
"${...}" syntax and treat HTML/SGML as an unstructured text string.

~~~
TeMPOraL
So with entity references, I guess it's a DAG then, with extra idiosyncratic
grammar. That doesn't change my main point: it's a structured language.
Expressions in a structured language should be built up through an API that
reflects that structure, and thus maintains the structural correctness of
constructed expression at all times. Not by gluing arbitrary strings together.

~~~
tannhaeuser
Except that HTML/SGML is a format _invented_ for authoring and delivering
semistructured text. At the risk of sounding arrogant, the idea is to have
domain experts (rather than programmers) create stand-alone documents that can
then be rendered and type-checked, can be refined by web developers using text
macros, page boilerplate, transformations/stylesheets, and script, and that
_can_ (but don't have to be) used for rendering dynamic content from markup or
other sources such as services and/or databases, while remaining self-
standing, autonomous, type-checkable documents in a larger workflow.

------
thms-rmb
Not exactly shiny technology, but XQuery seems to have a nice syntax [1]:

    
    
      element html {
        element body {
          element div {
            attribute id {"main"},
            "foo bar!",
            1 to 15,
            element footer { "this is the footer" }
          }
        }
      }
    
      <html>
        <body>
           <div id="main">foo bar! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15<footer>this is the footer</footer>
           </div>
        </body>
      </html>
    

1: [https://www.w3.org/TR/xquery-31/#id-
computedConstructors](https://www.w3.org/TR/xquery-31/#id-
computedConstructors)

------
lawn
I wrote my book[0] in Racket and the experience was quite good. The idea of
manipulating html as X-expressions is great and it allows you to easily
implement markup for sidenotes for instance.

[0]: [https://whycryptocurrencies.com/](https://whycryptocurrencies.com/)

~~~
watersb
Nice. Thanks!

------
elcritch
I don’t get why templates are such a pain?

> We've lost a lot of expressiveness: what if we wanted to create a nested
> list again? We could make it a template macro, but we have to do extra work
> to call it inside itself, and suddently we have an extra language to learn.

Not that I’ve used jinja aside from some Ansible, I don’t get the second
language part for templates or why templates are limiting? Even React’s syntax
really isn’t that different from a template as you need to enclose JS
expressions in curly braces right?

My favorite HTML server language is Elixir which has a Ruby flavored template
engine called using `<%= some_func(@val) %>`. It’s only 4 “tags” [1]. Well
maybe since it’s a functional language and everything is an expression the
semantics are simpler, mainly limited to whether or not to return a value.
Jinja probably is more difficult since Python control flow isn't an expression
so you add another layer (probably same in Ruby, Java, etc). Calling functions
is as easy as ensuring they’re in the scope of where it’s loaded (or just the
current scope when using the ~E sigil. So in the first example encapsulating a
sub-lists is just creating a function that returns a template. When compiled
it’ll create functions that return IO lists so it’s pretty efficient too [2].

Given that, I prefer having HTML look like HTML.

1: [https://hexdocs.pm/eex/EEx.html](https://hexdocs.pm/eex/EEx.html) 2:
[https://edmz.org/personal/2016/09/06/phoenix_templates-
_yup,...](https://edmz.org/personal/2016/09/06/phoenix_templates-
_yup,_they_are_just_functions.html)

~~~
ng12
> Even React’s syntax really isn’t that different from a template as you need
> to enclose JS expressions in curly braces right?

The difference is that they're real, actual JS expressions evaluated in the
current scope. Anything you can express in JavaScript you can express in JSX
without needing to learn anything new.

~~~
elcritch
Ah, I keep forgetting Jinja expressions can't be real Python. That makes more
sense. So really this article is relevant to only full template languages or
non-functional languages. edit: Looks like
[Selmer]([https://github.com/yogthos/Selmer](https://github.com/yogthos/Selmer))
is similar to EEx in the Clojure world.

------
didibus
Can someone explain the difference between an S-expression and an
X-expression? Even after reading the blog post I'm not following, seem like
the same thing to me.

~~~
tartoran
Started dabling recently so Im not an expert on the subject, but from my
understanding, Racket represents XML data as an X-expression. On the other
hand symbolic expressions aka s-expressions are the syntactic elements of the
Lisp programming language. Both programs and data are represented as
s-expressions: an s-expression may be either an atom or a list. So
x-expressions relate to XML

~~~
soegaard
Generating HTML is a common task. Over the years we have seen multiple
approaches in the Racket community. Representing HTML as S-expressions is
common. There is even two approaches in use `xexprs` and `sxml`.

There are other solutions, such as representing HTML as structures (often
called records in other languages). This is what I prefer - this allows a
little static checking. (See `scribble/html` or `urlang/html`).

Others prefer to work with `templates`.

My point got lost: There is more than one "Racket way" of working with html.

------
TylerE
The idea is right, but all the 'quoting and explicit list calls make this
super awkward.

If you're going to do it, do it right... use macros.

Of course, then you'd end up something that looks a lot like Haml
([http://haml.info/](http://haml.info/)) with parens everywhere.

~~~
fulafel
The Hiccup notation in the Clojure world (eg Reagent) works well, and it
doesn't need macros. You're still left with some quoting (for text inside
elements and attributes), but in practice most of these come from non-constant
values in code.

    
    
      (defn simple-component []
         [:div
          [:p "I am a component!"]
          [:p.someclass
           "I have " [:strong "bold"]
           [:span {:style {:color "red"}} " and red "] "text."]])

~~~
TylerE
Not a fan. Given that in a template context the first atom will always be a
symbol, all the : is just redundant. I despise visual noise.

~~~
fnordsensei
The `:` is not visual noise, it indicates that it is a keyword. Without it,
you're indicating that you're writing a symbol. Symbols are evaluated, so
keywords is a better choice given that they always are what they say they are,
whereas you could define `div` to mean `<p>`, point to a function, or any
number of other things.

You could write a macro to use symbol names literally, so that `div` always
means `<div>`, but then you'd have a macro where none was needed, and you'd
have no obvious way of using symbols in a non-literal/evaluated way.

Fulcro[1] lies little closer to what you're after. The above would be:

    
    
      (div 
        (p "I am a component!")
        (p :.someclass
           "I have " (strong "bold")
           (span {:style {:color "red"}} "and red") "text."))
    

This is since Fulcro defines the element tags as functions, which are called
in order, rather than as a data structure that's interpreted (a la Hiccup).

The immediate and obvious benefit of Hiccup over the function hierarchy is
that Hiccup can be trivially (and safely) seralized/deserialized.

1:
[https://github.com/fulcrologic/fulcro](https://github.com/fulcrologic/fulcro)

------
p4bl0
I think the power of X-expressions would have been better demonstrated with a
function that manipulates an HTML tree after creation, which is something you
don't really want to do if your HTML tree is represented by a big string
rather than an actual tree.

------
earthboundkid
This is JSX with parens.

------
animalnewbie
Something similar (and less of a parentheses hell) is Scalatags by the
amazingly prolific scala programmer lihaoyi. The good things about Scalatags
is that the same code can be used both in the backend and in the frontend. (I
don't use scala on the backend anymore but Scala.js is really good!)

~~~
lihaoyi
In one of my current projects, I'm using Scalatags on the server-side
generating strings, and then using the same templates on the client to
generate Preact.js vdom nodes to re-hydrate the server side templates. Cross-
platform, cross-backend templates is really a very nice thing to have!

