Hacker News new | past | comments | ask | show | jobs | submit login
HTML as a programming language – unifying HTML with Erlang (joearms.github.io)
103 points by rubiquity on Mar 16, 2015 | hide | past | web | favorite | 58 comments

I personally prefer using data structures as html as long as I can, then rendering the html to a string at the last moment. This has the advantage of being able to use the entire programming language on the html-y data.

In Clojure there are a bunch of tools for doing this. One is hiccup, it's for server side html rendering. You can define a function that returns a Clojure datastructure like so:

    (defn greeting [person] 
        [:h2 (str "Hey, " person)])

    (greeting "Paul")
    ;=> [:h2 "Hey, Paul"]

    (hiccup/html (greeting "Paul"))
    ;=> "<h2>Hey Paul</h2>"
There are also tools for doing this in clojurescript. My favorite here is called Reagent (http://reagent-project.github.io/). It's a minimal wrapper for react.js that appeals to me because I can focus on my code since there's less to know compared to Om.

I've always though of HTML as a way to hide the idea that it the markup is just an s-expression shared over a network. Indeed, Roy Fielding's work on ReST leverages the default paradigm of distributed computing using immutable data-structures in the first place.

What's so different about:

<html> <head>...</head> <body> ... </body> </html>


(html (head ...) (body ...))

Wouldn't we've been better off with the latter anyway?

"I've always though of HTML as a way to hide the idea that it the markup is just an s-expression"

This is a historical issue with HTML. It's supposed to be "markup". The original idea was that HTML documents would be mostly text with some tagging. Since it was just "markup", markers that triggered formatting operations, it wasn't considered necessary that a strict tree structure be enforced. HTML5 still tolerates and parses such constructs as "Plain <b>Bold <i>Bold italic </b>Italic </i> Plain". This may be a holdover from the way things worked in UNIX nroff/troff, an early markup language.

XHTML requires that the tags balance, which seems to put a lot of people off. I thought at one time that XHTML would replace HTML, but that didn't happen.

In retrospect, browsers were made too lenient. It probably would have been better if, after detecting an error, browsers put a red band across the page with an error message, then continued to display using default fonts and colors. Then we could have avoided years of struggling with browser incompatibilities due to non-uniform handling of errors.

(I'm currently trying to figure out why BeautifulSoup 4, the Python library, creates a broken parse tree and crashes for documents which contain "<head><head> ... </head></head>". "kroger.com" has that. You'd think that the web pages of the Fortune 100 would be better.)

> In retrospect, browsers were made too lenient.

The dark side of Postel's Law.

Other than the preference for the syntax, how would s-expressions make for a better markup language?

So much simpler to parse, so much less room for ambiguity.

No <b><i>mismatched</b></i> closing parens. No <p>optional close tags. No difference between compulsory close tags <script></script> or <img /> self closing tags.

But without a specialized editor, SGML is nicer to write.

SGML is nice for humans. S-exprs are nice for programs.

Easier to parse, but it would be close to impossible for humans to edit the real-world pages. Try turning any bootstrap template with their 10+ nested levels of tags into the syntax you propose, and then try moving things around in the editor, finding the right spot to append an element when all you see is something like )))))))), that would be crazy hard to do without errors. To make that work we would first need some kind of function syntax, so that deep nested blocks can be simplified.

Parent mentioned "specialized editor". What he meant was emacs + ParEdit, which alleviates these problems. With ParEdit, you don't navigate around and edit sequences of characters - you edit nodes in a tree - where each set of parens in the text represents a node and the individual identifiers are the leaves. It's awkward to use at first because you need to supress your usual text-editing habits, but the productivity gain once you're familiar with it is worth the training.

Besides, Lisp has the tooling for collapsing deeply nested structures into flatter ones if you need to, because one can use nested defines inside a function and later just call by name if needed. It just means the stuff that would've been more deeply nested will be defined earlier than it's container. Most of the time this is usually what you want anyway, because you're going to be reusing a lot of the structure elsewhere in the document - DRY becomes a lot simpler.

A lot of people get their start with HTML by just opening it up with .... whatever ... and fiddling with it. These people are not Lisp programmers, not by a long shot.

HTML is nice in part because it's pretty easy and accessible for people who are not programmers by training.

Do you really think "<foo></foo>" is more accessible to a noob than "(foo...)"? It's not like HTML is painless to edit, either.

In a vacuum, they might be the same, although like someone else mentioned, with parens, you eventually get the dreaded ))))))) somewhere.

It's not in a vacuum though: there are tons of tools and tutorials and colleagues and other things dealing with HTML as it is, and tons of people used to how it currently is.

The original question, "how would sexprs make a better markup language", was in a vacuum. At least that's how I took it, and for good reason. A discussion whose pivotal argument is "well, that's how we do things now" is neither interesting nor (after the first few times your idealism is stomped on) is it illuminating.

In my experience, I've not found this to be true. When writing lisp, I find that very quickly the parens just disappear. Even when I first started writing it. And balancing tags in *ML languages is not something I've ever found "easier". Both require a specialized editors for "power users" to be more productive.

All pages would be about 1/2 the size the are now. Think of the gagillions of moogaboots we'd have saved over the years! These migibits could have been used to promote world peace or even disseminating your grandmother's unsurpassed oatmeal cookie recipe! You pick!

"I personally prefer using data structures as html as long as I can, then rendering the html to a string at the last moment."

I'd go so far as to say that is the correct way to do it and anybody doing anything else is doing it wrong. Anything other than "immediately parse all incoming data to internal structures" and "serialize internal structures at the last possible moment" is just crazy insane to deal with, and unfortunately, when it comes to the web, "crazy insane" immediately leads to "insecure".

While I agree in part, I often find that page html isn't much like a proper data structure at all: it's littered with tons of presentational fluff like wrapper divs.

I find that HTML is usually more tightly coupled with the CSS than the associated logic (which is done with more traditional data structures). for this reason I find views written in programming languages can feel like a clunky abstraction over HTML, rather than a simplification of it.

Ah, yes, I should have gone into this. Somehow, hand a person an HTML data structure and suddenly they forget they're in a programming language. I'm not being sarcastic in the slightest, I see this all the time, I wish I had a name for it. (See also Ruby-style DSLs that somehow encourage you to forget you're actually still in Ruby, for instance.)

Anyhow, the solution to "repetitive HTML" is the exact same as the solution to "repetitive code", because it is repetitive code: Factor it.

Get used to this approach and honestly, the only thing that a conventional template is better at is large blocks of static HTML tags; otherwise, a "powerful, rich, awesome, wonderful" template language that everyone goes gaga over is just an inner-platform effect problem mistaken for virtue.

I'm also generally underwhelmed by the "'dumb' designer has to be able to edit it"... I'm sure someone, somewhere has that use case (I mean, don't bother replying, really, I believe you have this use case), but it seems to me an awful lot of people plan for that use case but it never actually manifests. I'm not convinced it's the common case.

I'm not sure I can speak for jerf, but I think the important part is to put off all that presentational fluff to the last minute, as part of your serialization.

Do you use hiccup as well as Reagent? Or must you commit to one or the other? Which do you prefer?

People use 'hiccup syntax' to mean the [:h2 "okay"] style of datastructures. Hiccup is actually the name of the (first?) clojure library that parses

    [:p.tall "hi"] 

    <p class="tall">hi</p>

Reagent is a clojurescript library that lets one write a Single Page App as clojure datastructures. Most of what reagent does is take a function that returns 'hiccup syntax' and turns it into a react.js component. One can also create components using Reagent by hooking into the :component-did-mount events.

There's a hiccup like syntax within reagent which produces output via clojurescript. So (:div (... )) in your cljs.core turns into a react component.

There's also kioo if you like the enlive approach better.

Any sufficiently complicated templating language contains an ad hoc, informally-specified, bug-ridden implementation of a turing complete programming language.

Segregating views from code was reasonable when most of our sites were mostly content. The occasional need for logic can be satisfied by string interpolation to run a programmable expression. Which is exactly what the old crop of templating languages have been doing.

However, this paradigm doesn't suit web-apps. A web-site can be thought of as a programmatically enhanced view, but a web-app is a programmatically constructed view. Construction calls for abstractions. We can either port back programming abstractions in the form of helpers and directives into templates, giving rise to innumerable templating languages with custom syntax and innumerable quirks (http://en.wikipedia.org/wiki/Comparison_of_web_template_engi...), or we could simply use code, the best tool for the job.

This is exactly what JSX does: it enhances code to be able to parse XML views, which helps us write well-organized front-end code with all the abstractions that only a programming language can provide.

Yes, but this stems from the fact, that people continue to bend the whole stack for what it wasn't designed to be in first place.

Sorry, but this is a trite argument.

It's visible to everyone that "the stack" is being rethought in that direction since DHTML became a thing (which was many, many years ago).

It does not matter much that it was not originally designed this way. it does work, it is still mostly backwards compatible. I could build an app in react today that works on both Chrome 40 and Mosaic (`NCSA_Mosaic/2.0`). I could switch set of views, add a transform in front of the virtual dom engine, replace the vdom entirely, render to canvas and then send images + linkmaps (so '90s), because the technology is so versatile yet simple.

The document model, in all its simplicity, with its elements and hyperlinks, has allowed us to build an enormous, completely new market for services with relatively few costs, that has been malleable enough to work on basically every device, use-case, etc. We stream video with it, process payments, we connected the whole world with it (people! not hosts).

It's like the old "if only unix weren't there". But of all the things that were launched on the wall, only unix stuck. Like the vhs, like the linux kernel, like tcp. It's obvious that despite not being technologically superior, there were benefits to all these in practice.

Hacker News is actually written in a similar way[0]. Here is the code to generate the lists page[1] (the code is a bit outdated):

  (newsop lists () 
    (longpage user (msec) nil "lists" "Lists" "lists"
        (row (link "best")         "Highest voted recent links.")
        (row (link "active")       "Most active current discussions.")
        (row (link "bestcomments") "Highest voted recent comments.")
        (row (link "noobs")        "Submissions from new accounts.")
        (when (admin user)
          (map row:link
               '(optimes topips flagged killed badguys badlogins goodlogins)))
        (hook 'listspage user))))
[0] https://github.com/wting/hackernews/blob/master/news.arc

[1] https://news.ycombinator.com/lists

I have always found something really off putting about mixing html with programming languages. Whether it be HAML or Rails or really anything. I like the separation of concern, and modularity of building an application that has files and folders for each feature or usecase. HTML is simple markup to semantically explain pieces of the web page. Dynamic features should be applied from their own folders and files and not mixed into some massive frankenstein file. It is messy, not semantic, difficult to debug and creates problems for other aspects of your application (DOM targeting, Styling etc.)

I disagree, HTML is a datastructure like any other, and it should be easy to build one without going through an untyped string or an auxiliary file. It's painful to make one html file per renderable item -- and debugging takes more time (once you've found who's responsible for rendering it, you need to check the corresponding template, so there's an additional step in your way.) There's no semantic in using the filesystem to organize your templates: it's the code that specify the meaning, and your programming language provides more organization units than your FS (or should we do "one function per file and one directory per class/module"?). (Also, the obvious filename typo vs static checking of function names; and the fact that your template is going to contain some rudimentary form of code or force you to obfuscate your intent even more.)

Which is why I don't like the proposal: it's not unifying HTML and Erlang, it's compiling string macros into Erlang. Is there any reasons not to embed the interpolation in Erlang directly?

    hello(N) ->
      Name = <em><? N ?></em>,
        <p>Hello <? Name ?></p>
        <p>The <#></#> lets you group
           multiple elements, that don't
           have a parent, as a single value.</p>
(Whether the <X></X> is doing simple string interpolation, or is HTML-smart is left for the reader to decide -- it's certainly overkill for server-side only code.)

> I have always found something really off putting about mixing html with programming languages. Whether it be HAML or Rails or really anything.

You could use XSL , i'm pretty sure you never do that.

Any solution that relies on "templating" involves logic in templates. And templating languages are there because they ALLOW separation of concern. A template is independent from the controller that called it. They just share a contract at the data level.

Totally agree. And actually, I find HTML in itself too verbose to begin with. Why require those close tags? So that one can see what tag is being closed? That is stupid, because in most cases, we're using just a few tags (DIV, SPAN) anyway, so this gives very little information. I'd rather use real open and close braces like most data-structures in modern programming languages.

Sometimes seeing the closing tag is rather useful for the very reason you mention, to know which tag is closing. The simple fact that once it was popular to use a comment to identify the id or class of the closed element at the bottom of a long file suggests it's a problem to consider.

But nowadays, the behavior of an element can be completely styled by CSS. So in most code, you will find a lot of DIVs. And imagine having 10 DIVs nested: you can't possibly tell by looking at the closing DIVs which DIVs they are closing... Unless perhaps you put also the classname on the closing tag (which isn't allowed or enforced or verified). So, as you can see, the closing tag has very little utility. It only makes the code less readable (as it takes space). And also, but this is secondary, it requires more bandwidth.

Well, first I would say that if somebody has ten nested DIVs then they're doing it wrong. But if the DIVs are formatted properly then it's usually not that hard to find the matching start tag. As for the class in the closing tag, that's what my statement about people putting comments with the closing tag is referring to. It's been done and was quite popular at one time. I'm willing to bet our editing tools fixed that problem simply by highlighting matching element pairs.

But in the end, if HTML went with <div></> instead of <div></div> then I probably wouldn't mind so much. But I can't agree that no closing tag is more readable because it takes less space, that makes no sense. It might look better.

I would be curious about bandwidth savings but I'm willing to bet in most cases it would make very little difference.

You just read my mind.

I'd much rather just use custom elements:

Assuming a library that makes declaring custom elements very easy[1]:


    <template is="quick-element" name="one-lorem">
      Lorem ipsum dolor...

    <link rel="import" href="one.html">

[1]: https://github.com/Polymer/core-focusable/blob/0.8-preview/d...

I always liked some of the ideas from Zope/Plone's template language, specifically the TAL (most basic) bit. When one adds macros/includes, some of the benefits fades a bit away: but it's nice to be able to have templates that can be rendered as-is in browsers, with a meaningful preview:

    <!-- ... you'd need to include static css etc --!>
      <tr tal:repeat="item here.cart">
        <td tal:content="repeat.item.number">1</td>
        <td tal:content="item.description">Widget</td>
        <td tal:content="item.price">$1.50</td>

With html5 one gets some of the same benefits for free -- I guess the basic insight is to allow there to be demo/dummy content that can be rendered as/is valid html(5) -- and have the templating system replace it gracefully.

Also of some interest is the xml/xsl-based theming support for Plone, allowing taking standard html, add a few rules, have diazo write the xsl -- and use the html (content and all) as a template:




(Note this is actually mixing up two different types of templating, even if both do text-substitution. One is more of the "string interpolation/macro expansion" (aka you could just have used m4 to make the html) -- and the other is more themeing related: twisting appearances while semantics stay the same. They're conflated mostly because semantic html mark-up doesn't a) quite work and b) isn't actually supported by CSS (independent of semantics, because structure confers meaning in html, so with different structure, comes a need to either morph the structure (diazo) or rewrite (parts of) the CSS.

The new way to side-step this issue, is to rather than standardize on good/sensible html-markup (aka: the zen garden approach that has worked for some 15 years now), but rather to move from html/xhtml/xml to json -- pretending that just because the tree is wrapped up in curly-braces and semicolons rather than bracket-tags, it's no longer a tree, and order and levels, and siblings magically cease to make a difference (aka the "lisp pipe dream -- we're too cool for assoc, we already have cons"-approach). But as long as we're on the web (and probably in many other places as well, such as desktop ui, we'll have the equivalent of structured documents, where both structure and tagging makes a difference -- and the need to go from various trees to various documents, and to map differently structured documents to each other. And interpolating simple plain-old-data-trees into a template for a document is going to be a different task from translating parts of one document to another. Even if both data and documents are represented as json (or xml or html or xhmtl or...)).

This Erlang web framework already has something like this:



    body() ->
    {ok,Pid} = wf:comet(fun() -> chat_loop() end),
    [ #panel{id=history}, #textbox{id=message},
      #button{id=send,body="Chat",postback=chat,Pid},source=[message]} ].

Also comes with bidirectional Websocket connection support.

It is based on a similar project called Nitrogen.

Does anyone else get the feeling of "Joe has rediscovered templating engines, but in Erlang"?

This is still neat; I just want to make sure I'm not missing anything.

Congratulations, you've reinvented PHP, kind of.

He already invented it 3 years ago: http://erlang.org/pipermail/erlang-questions/2012-February/0...

Also there was a talk about Erlang where Joe Armstrong was talking about EHE, but I couldn't find it. I thought it was a joke, but apparently it wasn't.

That's not the bad part of PHP. Rather, it's the part of PHP that let it take over the world despite its manifold flaws.

The latter is undeniably true, even if the former is debatable. I've had to maintain code where PHP variables were assigned from a database then echoed directly into javascript functions and broke more than once because of encoding issues or a lack of necessary escaping -- being able to do crazy things like that is very flexible and fast, but it can also lead to some horrible messes if you don't know what you're doing.

This looks surprisingly similar to how the Nitrogen framework uses Erlang records to wrap around HTML elements and jQuery actions, e.g. as in: http://nitrogenproject.com/demos/simplecontrols

All markup languages converge toward Turing completeness, just like all programming languages converge toward Lisp. Just use a homoiconic language--a language where code is data and data is code--and you won't have these kinds of problems.

Also reminds me of Pollen, for the inestimable Racket environment, which was created by M. Butterick to typeset "Practical Typography".


I might do something like React JSX, maybe called ERX. I do think it opens up a hole though in doing business logic the wrong place. I know in Elixir it might be easy to do with the meta programming stuff.

That should be pretty easy with parse transforms, here is an example for embedding JSON:


As another comment suggests (https://news.ycombinator.com/item?id=9215580), this would allow you to keep everything as a data structure until the last minute.

In regards to business logic, I think you just need to be strict when writing your application with the idea of what a 'view' is. Although React may seem like you are violating separation of concerns, in reality view logic and templates are already tightly coupled.

When I read that title, all I could think of was the apocryphal "Can I use HTML with variables to make a hockey MMO" thread from GameDev.net.

This one is even older, but I'm still not sure its the original http://www.gamedev.net/topic/128827-variables-vs-html/page-3

That's the one!

I really think you should use Variables++ instead.

The sad thing is, XML, and thus XHTML, has this. And it's nowhere near as ugly as this, which is saying something, because "lol, XML".

If what a person wants is cross-referenced elements in an XML document, then that's what they should use: https://msdn.microsoft.com/en-us/library/ms950811.aspx

If what a person wants is logic in their HTML, then they're standing on a slippery slope that ends in Classic ASP, PHP, and other wailings and gnashing of teeths.

Moments like this I wish people still used XSLT...

This is powerful. It streamlines everything for efficiency. It might not be the best solution at this moment in time but the idea of programming with HTML has value. Especially as web apps get bigger and more powerful.

It was nothing HTML was ever designed for and this kind of programming failed horribly in the past, see PHP's frameworkless go-to mode of programming.

PHP's past frameworkless mode of programming (though even goto's were shunned, if I think back a decade to when I was writing that sort of PHP).

You are right though, that it can get messy very quickly. But there is a case to be made for it in some circumstances; at least in terms of being able to render a page server-side as well as having it available as an API. I don't know enough about Erlang to say whether this is a good way of doing so, however, but it can be nice to have your templates with the interpolation points and small bits of display "logic" (if, then, etc.) all separate from your proper API written in a proper style.

This is neat, but a really bad idea over all.

Yea Its a cool exercise into what can be done. But ultimately not a road that I personally would like to travel..

basically another form of JSX. Looks cool but don't think I would prefer this anyways...

Applications are open for YC Winter 2020

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact