Extending Emacs with Fennel (2024)
andreyor.st144 points by Bogdanp 3 days ago
144 points by Bogdanp 3 days ago
Fennel absolutely rocks for creating games. It integrates with TIC-80 (open source fantasy console) and also Love (game engine) and PICO-8. Lots of blog articles on getting started. Check it out!
If so can you reccomend (link here) some of the resources which got you started?
FWIW there are blog posts from the same author of the Emacs setup: https://andreyor.st/tags/game1/
I use this for playing with Löve2D: https://sr.ht/~benthor/absolutely-minimal-love2d-fennel/
Can't say I made anything worth mentioning. There are some bigger templates available that I am sure do more useful things, but I prefer something small enough that I can see what is going on.
Worked fine even for getting things to run in LoveDOS, a port of some older Love2D version to MS-DOS. In practice compilation was a bit too slow for comfort, so a better way was to pre-compile the fennel-scripts to Lua and just run those.
I installed some LSP server for fennel that comes with optional built-in code completion for both Love2D and TIC-80. Works well in emacs.
Emacs has cl-lib. If you come from Common Lisp you will be 90% at home, minus closures and a few rough edges. Still, PAIP code has been ported to Elisp:
https://github.com/yfuna/paip-el
The original one:
https://github.com/norvig/paip-lisp
Paradigms of AI Programming:
https://upload.wikimedia.org/wikipedia/commons/d/d4/Peter_No...
I thought we had closures now with lexical scope being added in the last few releases
Then paip-el should be updated for the latest cl-lib compatibility standards. For sure it would be far less boilerplate code, except for the strings formats of course.
What makes a modern Lisp? I am aware of Fennel and Jannet. Anyone havng experience with one of those or another one I am not aware of?
Janet (with one l) is modern because it is, well, new. It doesn't need to carry the historical baggage of Common Lisp. It has many data structures, a concurrency model, it is suitable for functional programming and for object-oriented programming. It has libraries for common tasks and is well documented.
> Janet (with one l)
Typo, it should be: “with one n” (as the earlier commenter wrote “Jannet”). It took me a while to parse this, I was searching for the nonexistent “l” embarrassingly long.
Common Lisp, which I would consider the most modern, has convenience features which most other languages (even other Lisps) lack. CLOS, macro expansion, and, of course, the condition system.
Do you consider Common Lisp more "modern" than say Scheme or Racket?
As far as I know, the CL spec hasn’t been updated for 30+ years, and most of its design is far older.
Don't know much about Racket, but CL has type dispatch:
(defmethod join ((a String) (b String))
(concatenate 'String a b))
;; example: (join "abc" "def") => "abcdef"
(defmethod join ((a Integer) (b Integer))
(parse-integer (format nil "~D~D" a b)))
;; example: (join 123 456) => 123456
And rudimentary support for ADTs: (deftype Low-Score ()
'(Integer 0 20))
(deftype Normal-Score ()
'(Integer 21 79))
(deftype High-Score ()
'(Integer 80 100))
(deftype Score ()
'(or Low-Score Normal-Score High-Score))
(But note that deftypes aren't allowed to recurse.)CL also has first-class support for debugging with things like describe, step, and trace built-in.
EDIT: Yeah, the CL spec dates from 1994 and a bunch of things which we would expect nowadays (networking, POSIX,...) are provided by external libraries rather than being part of the spec, but in various ways CL is way ahead of its time.
I wouldn't consider a "moderness" comparison between CL and Scheme to be useful. They're too different in intent and capabilities.
CL has a more-or-less frozen standard, in the sense that it's unlikely to have an update. Scheme gets updated standards, but they seem to focus on refining Scheme rather than adding "modern" features. Both are very extensible and people do add modern features as implementation extras or libraries.
I can't comment about Racket. As an outsider, it appears to be a playground for hardcore CS types to experiment with different programming language features, which suggests it's the most "modern." That's just the impression I get, though - feel free to correct me on that.
And yet we're still catching up on having features from Allegro Common Lisp and LispWorks more widespread across mainstream languages, where Java and .NET ecosystems are the closests in terms of IDE capabilities, graphical debugging, runtime introspection, JIT and AOT on the same package,.....
Which goes to show how many lessons the industry failed to learn on those 30+ years.
Which lisps lack a macro expansion system?
R7RS (small, at least) doesn't seem to have macro-expand. R6RS also doesn't appear to have it.
So the modern scheme specs. (I'd argue putting small in there is unfair considering its intent and the actual implementations of r6rs do offer expansion, e.g. chez, guile, racket)
R6RS has syntax-case macros which is superior to Common Lisp macros in every respect, they're both hygienic and can be used to implement a sloppy macro system if one so wishes.
`syntax-rules` is very good and you can do a whole lot with them. However, you are limited to template -> pattern transformations, and there are plenty of macros that you cannot write this way. (E.g. anything requiring a predicate on the source syntax that you can't express in the template language, etc.) For that, you need the full power of procedural macros.
Racket improves on Scheme: its macros are fully hygienic whilst not being limited to template -> pattern transforms. See https://docs.racket-lang.org/guide/macro-transformers.html
EDIT: syntax-case -> syntax-rules; R6RS specifies the latter—I believe the former is a Racket construct equivalent in power to `syntax-rules`.
I think the parent meant that R6RS has `syntax-rules`, which has enough power to implement CL `defmacro` as well as `syntax-case`.
My mistake: R6RS has `syntax-rules`, not `syntax-case` as far as I can tell. However, `syntax-rules` and `syntax-case` are equivalent in power. [1]
It does not have the same power as `defmacro`: you cannot define general procedural macros with `syntax-rules`, as you are limited to the pattern-matching language to compute over and construct syntax objects.
[1]: https://docs.racket-lang.org/reference/stx-patterns.html#%28...
I think you got your wires crossed. R5 and R7 only have `syntax-rules` macros. R6 has both (`syntax-rule` can be trivially defined as a `syntax-case` macro).
R6 having `syntax-case` macros is one of the more controversial things about it; a surprising number of implementers don't care for them.