@jakob Very cool, thanks! I think the Janet parts need correction though, the Fennel link goes to a Racket website.

@jakob Actually, there's one more such Fennel link in the preceding Hy section.

@wasamasa I think I need to give my links a quick look over. Seems I was a bit haphazard with org-insert-link.

Thanks for pointing that out, too. I've fixed it.

@wasamasa I think that's the rest of it, aside from the Kalibera et al. citation lacking a link. Do you mind if I thank you for your corrections at the end of the article?

@jakob Sure, go ahead. I'm kind of sad figuring out the linked bug report for CHICKEN is beyond my current expertise level. All I've found so far is that the bug goes away if you replace the reduce call with foldl from (chicken base), but that just sweeps the bug under the carpet.

@wasamasa Ah, that's right, I almost forgot that you contribute to CHICKEN.

Admittedly, I should have been using CHICKEN's fold in the first place since it's in SRFI-1 and I already had that imported. But, better to not let a compiler bug go under the radar.

@jakob really enjoyed this post; thanks for sharing. I have a bunch of questions but first of all I have to ask: what on earth was it like to have your dad teach you Emacs at age nine? (I have two kids age ten and twelve, and I've been teaching them TIC80 and love2d but sticking with more conventional editors so far)

@technomancy Haha, I knew someone would mention that. I wasn't technically apt enough at that age to have learned the typical CUA-style keyboard shortcuts, so learning it didn't feel foreign or unnatural in the way that it might for an experienced programmer being introduced to Emacs. I was mostly writing HTML by hand at the time, and I remember being able to use the menu bar to insert tags. It was a nice experience.

I should find my old laptop and see if I can pull the config off of it.

@technomancy I think you're doing the right thing by sticking to conventional editors for right now. My situation probably made more sense for the time -- I'm not sure of any other accessible options that existed when I was nine years old.

@jakob haha, awesome.

anyway, a few notes about the Fennel section.

> Unfortunately, you can't destructure everywhere. You can't write this, for example

the reason that example fails is not because each doesn't support destructuring but because the arguments are in the wrong order; put the _ first and it'll work fine.

I suspect the reason luajit is running so slowly for you is that the JIT hasn't had time to warm up and perform optimization traces. does the performance improve if you run (say) thousands of passes instead of just one?

> there's no way to send something from a source code buffer to the REPL.

C-c C-k should reload the entire module once you have a repl buffer open. The repl buffer just uses inferior-lisp-mode, so all the normal bindings for that should work the same. if you run into issues with that please open an issue!


> I suspect the reason luajit is running so slowly for you is that the JIT hasn't had time to warm up and perform optimization traces. does the performance improve if you run (say) thousands of passes instead of just one?

I actually thought the luajit performance was quite good. I wanted to avoid rigor here because I'm a bit of a statistics noob, but I'll do a run where I try to get to i.i.d iterations. I should probably do something similar for Racket, which is also JITed.

@technomancy As for the other comments, I'll get working on putting those into the errata. Thanks a bunch!

@jakob I wrote a similar "comparative lisps" post in 2013 but it was quite a bit more superficial: https://technomancy.us/169
@jakob yeah, the problem is that measuring performance is such a nuanced problem; it's hard to do a comprehensive job.

that said, with tuning LuaJIT should be able to approach within 1.1x the speed of C++ according to this guy who built a smalltalk VM in it: https://old.reddit.com/r/lua/comments/htqn0t/luajit_once_again_nearly_as_fast_as_the/

@technomancy For sure. I've done a bit of reading on statistically-sound benchmarking, since we do some comparisons of sequence alignment algorithms in my lab, but I still defer to my statistician friends for help with the design and interpretation. I thought the most appropriate thing to do was to just wave hands and give the disclaimer that it is complete hand-waving.

Benchmark is still running at the moment. Ten iterations since I've started.

@technomancy One difference between that success story and mine is that I haven't done much to optimize my raytracer. In all implementations, it's a rather naïve translation of the underlying equations.

@jakob @technomancy Speaking of naive, I'm wondering now how much sense it would make to contribute an Emacs Lisp solution...

@wasamasa @technomancy I considered it out of morbid curiosity. I'm sure the Common Lisp version wouldn't be too hard to port over

@jakob @technomancy I thought so as well, but nope. There are glaring deficiencies in cl-lib/eieio that make this surprisingly hard:
- with-slots is incompatible with cl-defstruct and expects cl-defclass.
- cl-defclass can be made to create functions like cl-defstruct, but fails when using cl-defmethod because it for some reason creates predicates and clashes with what cl-defclass generated.
- with-slots can be made to work with cl-defstruct, but my macrology is more of a sham than shim and fails with even wilder errors than with the previous approach.

I'm pondering to instead rewrite this in a more idiomatic way without option types, but that would require actually understanding the code. Maybe another time.

@wasamasa @technomancy thanks for trying, at least. Perhaps I'll have a go at it this weekend when I have a little more time.

@technomancy I've incorporated your corrections to the article. My erratum is becoming more of a "change log" at this point, since I worry people would take my word for it and ignore the erratum. I'd feel bad misleading people about Fennel.

Pending results on benchmark, which I'll incorporate to the article when I get them. I've moved it to a different machine that doesn't have a faulty RAM stick.

@technomancy Running it on the machine with `time' had a real duration of 0m57.982. Using lua_benchmarking,

Mean: 86.477030 +/ 9.725198, min 59.790374, max 108.472983

So... I suspect there are some confounding factors, but there isn't a massive, noticeable difference coming from the JIT warmup.

I tried with --nogc, but it panicked rather quickly. Again, I suspect this is more of an issue with my code than LuaJIT or Fennel. I seem to be consing quite a bit.

[1]: github.com/softdevteam/lua_ben

@jakob some style suggestions: https://p.hagelb.org/0001-Some-style-changes.patch.html

mostly based on a cursory reading of the code. removing pack in particular seems to have a noticeable performance improvement impact; it went from 2m30s to 2m12s on my machine in a very unscientific test. since you mentioned a lot of consing is happening I'm going to test it out with the new generational GC in Lua 5.4 to see how that changes things.

@technomancy thanks for the patch! I'll merge this in.

Since you're actually looking at the code and bound to notice it at some point, I'm going note that `degrees->radians' is a really embarrassing mistake I made while going through my university notebook, seeing π/360 in a formula, and thinking "oh yeah it's converting to radians". It works fine because I'm not using it to convert any values outside of that formula, but it's probably very confusing if you were to come across the function.

@jakob lisp is more than just a programming language. It's literally math, (polish notation).

@rage Certainly. I was more interested in Lisp as a programming language for this article, but there's no doubt more I could have spoken about w.r.t the influence McCarthy's paper had on PLT research more generally.



> "The Many Faces of an Undying Programming Language"
> http://jakob.space/blog/thoughts-on-lisps.html

Nice article, well written and clear, thank you!

I hope did not mind if i write some little notes about the common lisp part

"Common Lisp is dynamically scoped, rather than lexically scoped."

Not exactly: as far as i know, variable in CL are lexically scoped unless
declared special using, for example, defparameter or defvar


(defparameter *baz* 1)

Yes CL is a lisp-2 but because (lambda () ...) is a actually a macro that
expand to #'(lambda() ... you can write something like

((lambda (x) (* x x)) 2) ; => 4

this surprised me the first time someone shown me that. :)

And, someway, it keeps surprising me even now :-)

This is my comments to the article, i strongly believe we need
articles like your, that compares different lisp dialects, so i wrote
this message to try to contribute to it, i hope my comments did not
annoyed you! :)



@cage thank you for the kind comments!

About scoping, this is correct. @cwebber pointed this out about half an hour ago, so that correction's made it into the current version of the post.

> @cage [1] thank you for the kind comments!

Thanks to you for writing this article, i think i am going to suggest reading it
to people that wans to grasp this group of languages.

Sorry for the duplicated comments about the scoping, i skipped the
errata at the end :(


> i think i am going to suggest reading it to people that wans to grasp this group of languages.

I feel honored :) I'm glad you feel it would be useful for that

> @jakob


> I hope did not mind if i write some little notes about the common lisp part
> "Common Lisp is dynamically scoped, rather than lexically scoped."

Sorry, i missed the errata at the end of the article. :(


@cage no worries, I updated it very recently, so it's possible you were looking at the version before I incorporated the fix.

In either case, I appreciate that you took the time to point it out to me :)


I use the '->' convention in my function name a lot, i think there is
some some little schemer hidden inside me! ;-D ;-D

@jakob Very cool article! Not quite the same, but I'm at least somewhat reminded of this history of the influences leading up to Go by henesy https://seh.dev/go-legacy/
@allison @jakob Go is quite cute, yes :blobcatcomfy:

i use nim these days, but if someone were to pay me to write go code i would not hate life.

if someone tried to pay me to write c++ i would have to spend half of the money on alcohol.

@jakob buuuuuuuut, I'm no lawyer, but, when you publish a Clojure application, you're not distributing a copy of Clojure
you're either referencing it in the source code of the application (this is a separate module) or you're compiling it into a java class (this is no longer te source code of Clojure) so, as long as you didn't patch the clojure version, I don't think a Clojure application is derivative work, and thus, is not subject to the Eclipse license???

@jakob aaaah, ok, that's on the gpl side
I was thinking of software released as public domain, which wouldn't have any problem *shrug*

@efi yeah, public domain and more generally permissive licenses such as MIT/BSD/zlib won't have any issues linking to the Clojure stdlib.

I'm a staunch advocate of the copyleft ideology, however, so I prefer to license the software I develop myself under protective licenses.

@jakob at risk of enraging the lispers... what about typed lisps? (like Carp, or Typed Racket)

@grainloom I've looked at Karp very briefly in the past. Since performance is a concern for me, it may be worth looking into again, but the documentation still warns to "[not] use it for anything important just yet!"

Typed Racket is a bit more mature, and the type declarations don't feel too intrusive to me. (They seem close to CL's `declare'). I'll try it out when I give Racket a proper look.

Sign in to participate in the conversation
Mastodon @ SDF

"I appreciate SDF but it's a general-purpose server and the name doesn't make it obvious that it's about art." - Eugen Rochko