4 ms·
That is why I like Hiccup/ Clojure so much: https://github.com/weavejester/hiccup https://github.com/weavejester/hiccup It is very natural to produce something
by kaliszad 3y ago
That is why I like Hiccup/ Clojure so much: https://github.com/weavejester/hiccup https://github.com/weavejester/hiccup It is very natural to produce something resembling a document in pure Clojure data structures and then just convert it to valid HTML. I think, Reagent has some hiccup extensions that are nice like writing the class or id with a . or # notation right in the keyword describing the tag. So there probably still is some space to improve the ergonomics and probably performance. Concatenating strings still wins performance wise by a lot.
- wryoak 3y agoOoo that’s slick
- i2cmaster 3y agoThe LISP people were right to make trees essentially a first class data structure.
- mbork_pl 3y agoLists, technically, but nestable lists are indeed basically trees.
- singularity2001 3y agoThe problem with lists as tree is that there is no universal way to distinguish a:{ b c:d } from a:{ b:(c d) } which is why we need proper maps as first class citizen for "the next lisp"
- kaliszad 3y agoClojure does have maps as a first class citizen (besides sets, vectors and lists). Then there is clojure.walk and other namespaces suitable for tree manipulation. https://clojure.org/api/cheatsheet https://clojure.org/api/cheatsheet Using trees of these collections is quite customary in Clojure - on the front-end you might keep the application state in a single atom, like re-frame does and update various branches of it using events/ effects and listening on changes to those branches using subscriptions. This approach work for us at orgpad.com quite well.
- singularity2001 3y agoYet what we really need is nested MAPS as first class data structure: a{ nested:tree with:{lots-of:data and:more}}
- maleldil 3y agoSee Clojure maps, Fennel tables and Janet structs/tables. https://clojure.org/guides/learn/hashed_colls#_maps https://clojure.org/guides/learn/hashed_colls#_maps https://fennel-lang.org/tutorial#tables https://fennel-lang.org/tutorial#tables https://janet-lang.org/docs/data_structures/structs.html https://janet-lang.org/docs/data_structures/structs.html
- kazinator 3y agoAlthough one way to generate HTML is to construct a structure with objects and then walk it to produce text, an alternative approach is possible whereby our HTML-in-Lisp syntax is a macro language that compiles to code that directly generates HTML without the intermediate object. This could be quite optimized to coalesce the text where interpolation isn't happening, and do constant folding in general. E.g. using Common Lisp as an example, this: (html output-stream ((a href "https://example.com") "foo")) could translate to the code: (write-string "<a href=\"https://example.com\">foo</a>" output-stream) which just dumps a string literal to the stream. One issue in Common Lisp html generators is that if you want to use the backquote syntax for it, you're steered toward an implementation that just lets the backquote do its job of constructing the list, and then walk the list. The reason being that backquote expands in an implementation-defined way. If backquote expands to a macro syntax like Scheme quasiquote, you can suppress its evaluation and then walk it yourself to give it your own meaning: (let ((url "https://example.com")) (html output-stream `((a href ,url) "foo"))) Here, html could intercept the quasiquote syntax, walk it itself and spit out code like: (let ((url "https://example.com")) (html output-stream (write-string "<a href=\"" output-stream) (html-write-attr url output-stream) (write-string "\">foo</a>" output-stream))) Historically, an example of a Common Lisp HTML formatter which walks a constructed nested list object is Tim Bradshaw's htout library. An example of an efficient generator of write-string calls is CL-WHO. CL-WHO doesn't use backquoting for interpolation. The code template uses keywords for indicating expressions that are HTML tags. Other expressions are implicitly Lisp to be executed. Inside evaluated lisp, the htm macro switches back to HTML templating. E.g.: (with-html-output (*http-stream*) (:h4 "Look at the character entities generated by this example") (loop for i from 0 for string in '("Fête" "Sørensen" "naïve" "Hühner" "Straße") do (htm (:p :style (conc "background-color:" (case (mod i 3) ((0) "red") ((1) "orange") ((2) "blue"))) (htm (esc string)))))) which, according to the documentation, generates code similar to: (let ((*http-stream* *http-stream*)) (progn nil (write-string "<h4>Look at the character entities generated by this example</h4>" *http-stream*) (loop for i from 0 for string in '("Fête" "Sørensen" "naïve" "Hühner" "Straße") do (progn (write-string "<p style='" *http-stream*) (princ (conc "background-color:" (case (mod i 3) ((0) "red") ((1) "orange") ((2) "blue"))) *http-stream*) (write-string "'>" *http-stream*) (progn (write-string (escape-string string) *http-stream*)) (write-string "</p>" *http-stream*)))))