Show HN: Dak – a Lisp-like language that transpiles to JavaScript
daklang.comHi HN, author here. Happy to answer any questions.
I had an itch to make a lisp like language that was a thin layer on top JavaScript. Something that could leverage the thriving ecosystem that exists around JavaScript. It's brittle, hot off the oven.
Besides being a fan of parenthesis, I think macros fill in a gap that the JavaScript ecosystem today fills in with one-off compilers, bundler plugins and such. Macros can't do everything, but for example I think they have the potential to enable things like JSX, Solid and Svelte style libraries.
Take the tour to get a feel for what it can do and play with the live code in your browser! Interesting, in the CLJS space we recently got two new libraries in this space: https://github.com/squint-cljs/squint Which is a thin layer on top of JS https://github.com/squint-cljs/cherry Which is closer to CLJS semantics and data structures but compiles to .mjs files without any advanced optimizations etc. I'm a huge fan of Clojure and have had a lot of fun building things with it. CLJS on the other hand has felt heavy to me, from a browser performance and dev tooling perspective. Clojure startup time always affected me more so with CLJS projects. I hope these two projects alter the landscape for the better! Besides those aspects, Dak is different than these two specifically in that it tries to provide something closer to a minimal 1-to-1 language feature mapping to JavaScript as the base, with a goal of having essentially no runtime. The clean room implementation has downsides - Squint and Cherry can reuse Clojure tooling like clj-kondo etc, which Dak cannot. On the other hand Dak is small, the transpiler is under 2k lines as I write this. It can run on virtually any modern JavaScript runtime (all browsers, node, deno, bun etc). Looks interesting. I hope to start using an s-expression based version of javascript after I get more familiar with the latter. Maybe you also want to consider comparing Dak to other attempts in this direction in order to help generate more interest in your work: https://github.com/anko/eslisp/blob/master/doc/comparison-to... Thanks for the feedback. I'll add some notes comparing it with other attempts like you suggested. I'm enjoying reading your transpiler[0], especially how well you use generator functions. Currently I'm building a similar language in a more opinionated object-oriented style, yet I still find yours inspiring. 0. https://github.com/daaku/dak/blob/main/packages/transpiler/s... Thanks! My fear taking this path is around performance. I've not done any profiling yet, and I'm hoping I don't regret taking this path when I get around to it. Well you know what they call un-optimized code? Shipped :) Nice work. A few years ago, I made something similar out of lumen[0] by tweaking the reader to support clojure style literals. I used hyperapp[1] as a lightweight library for react/elm style applications with a hiccup-like syntax. The code ended up looking like I'd intended to develop my own mini-lisp with the same syntax, but got sidetracked by other projects. Maybe someday I'll get back to it. (Currently, I'm deep in the weeds trying to learn how to write a dependent typed language that compiles to javascript.) [0]: https://github.com/sctb/lumen
[1]: https://github.com/jorgebucaran/hyperapp Nice! My goal in Dak is to reach a point where macros can allow transforming hiccup like syntax to hyperapp or React like function calls, or original hiccup style optimized string concat, or lit-html style template string generation. I know I could use all these for different use cases. Maybe dumb question since I only have experience with a few lisps (Common Lisp, clojure and scheme) but why is this “lisp like” and not a “proper” lisp? It looks like a lisp for me with its “code is data” (homoiconic) bit and s expressions. Describing stuff as Lisp-like is a good way to sidestep arguments about "proper" Lisp. What even is a proper Lisp? http://steve-yegge.blogspot.com/2006/04/lisp-is-not-acceptab... Huh it's orthogonal but basically Clojure is an attempt to answer all those four problems, right? Bypassing the which LISP problem by canonical implementation on top of host VMs (of which there are JVM, CLR, JS, Dart and BEAM), bypassing the spec, bypassing the whole object-oriented problem by impure functional approach, and having a BDFL on the top. Anyway, back to the main point, thank you for the article. I'll try to play around with Dak later today and see if I can use it to do something fun. Play is better to learn something after all. I've enjoyed defending the claim that Perl5 is a Lisp, just instead of being a Lisp-1 or Lisp-2 it's a Lisp-5ish. Indeed Kent Pitman is on the record[1] as saying that Scheme is not "a Lisp" 1: https://groups.google.com/g/comp.lang.lisp/c/Bj8Hx6mZEYI/m/6... and now I just miss Erik Naggum and his contributions to lisp discourse. Really reminds me of Parenscript[0], which is a subset of Common Lisp that transpiles to JS with no runtime. It's basically a thin skin around JS and it feels more like writing JS with a Lisp syntax. What I feel is missing from Parenscript is runtime macro-expansion, hard to do without using JS to build the AST. Ah, I remember seeing this a long time ago. It seemed like something CL fans would enjoy, but to me it felt verbose. I guess this is my Clojure preference showing. Regarding runtime macro-expansion - since Dak is written in JavaScript, it comes for free. Neat. So in a single sentence, you could say "As Janet is to Clojure, Dak is to ClojureScript". Hmm, name is a bit too close to another language - darklang wasn't that effort put aside? The startup is no more, but the founder is still going strong at it. In Australian slang, to da(c)k someone is to pull their pants down to humiliate them.
Where h is the raw function for hyperapp, not a macro. (h 'div { class: 'main }
(h 'div {} ....