Readit News logoReadit News
uvas_pasas_per · a month ago
Lisp is very cool. But one thing I do not like is that the syntax style `(fun a b c)` loses out to the less-symmetric "OO" style `a.fun(b, c)` when it comes to IDE auto-completion. And for me the IDE help is important to provide a smooth developer experience and minimize wasted brain energy. I'd like to find a way to make the editing and auto-completion work better. I think the way IDEs (and maybe our brains) work is: "here is a thing X, now what can I do to/with it?". That translates to typing in your editor: "X.[cursor here]", and then the IDE lets you see and search the things you can "do" with X. But if, in Lisp, you write "([cursor here]", you are immediately confronted with: "what is the signature of that function again?", but the IDE has nothing to go on. Maybe there is different style of editing, where we could type the arguments, and then trigger the auto-complete.
lenkite · a month ago
In Clojure, this is merely (a/fun b c) or (. a fun b c) depending on whether a is a namespace or an object. Autocomplete works wonderfully. I would strongly urge you to try a coding session using Cursive so you can objectively refactor your obsolete LISP opinions.
bcrosby95 · a month ago
I don't know about other lisps, but Clojure has namespaces and that's good enough for me. So you can type "(foobar/" and get a list of functions in the foobar namespace.
xigoi · a month ago
Janet kind of has this too: if you import a module with (import foo), all the imported bindings will be prefixed with foo/. Also, this can be avoided by writing (use foo) instead.
tmtvl · a month ago
Common Lisp also has namespaces, you can type '(asdf:' and get the functions ASDF provides.
kqr · a month ago
Haskell sort of has this. You type (_ a b c) and the compiler tells you which methods would make sense there based on all three variables (so in a sense it is even more useful.)
uvas_pasas_per · a month ago
Do you mean you run a build and it tells you in the error message? Or is there an IDE/editor where you could hit a key-combo with the cursor on that line, or near the `_`, and it would show a popup of possibilities for auto-completion?
thegeekpirate · a month ago
Odin's language server calls it "fake methods".

https://odin-lang.org

https://github.com/DanielGavin/ols

tmtvl · a month ago
What do you do if 'a.<tab>' doesn't work because it's not 'a.fun(b, c)' but 'b.fun(a, c)' or 'c.fun(a, b)'?

Also think of autocompletion for 'var x = new' to 'var x = new ByteArenaFactory()', the way you get from nothing to 'ByteArenaFactory' is the same way you get from nothing to '(fun a b c)'.

everforward · a month ago
I think this is more familiarity bias and the presence of an enforced type system than a necessity of auto-complete. In the same way that `a.` auto-completes to methods of `a`, `(fun ` could auto-complete to a list of in-scope variables that satisfy `fun`'s type signature. A lot of lisp is untyped though, even in variants that have support for it.

I also think there's some familiarity bias to the OO style. I don't find it particularly natural, though that's subjective. I often know what I want to do, and have to find the object that has the method. E.g. I know I want to read a particular header, but is it on Request, or on Request.Headers, or are headers passed in as a separate object? It feels cleaner to do something like `(get-header "SOME-HEADER" ` and have the IDE tell me I need to pass in `(get 'headers request)` or similar.

xigoi · a month ago
Janet, like some other lisps, has the arrow macro, which allows you to write in the “OO” style.

  (-> a (fun b c))

zelphirkalt · a month ago
Ah neat! In Guile I use threading/pipelining all the time with a small macro:

    (define-syntax ->
      (syntax-rules ()
        ;; first expression is left unchanged
        [(-> expr) expr]
        ;; take from the back, wrap other calls
        [(-> expr* ... (op args* ...))
         (op args* ... (-> expr* ...))]
        ;; make parens unnecessary in trivial case of no further arguments
        [(-> expr* ... op)
         (op (-> expr* ...))]))
Janet already having this ... Reading many good things about Janet in this discussion.

uvas_pasas_per · a month ago
Something like this combined with some IDE smarts to offer up the possibilities for `fun` after I type `(-> a` ... that could be very cool.
worthless-trash · a month ago
I think that threading macros is different to method chaining (at least to my understanding), method chaining works on the object returned, and threading macros can work on raw data or objects.
zelphirkalt · a month ago
When I see languages like this, I always wonder, how far the ecosystem is. I have used GNU Guile a lot and there are quite a few libraries for it, so that one can do almost anything. Web things are coming, but maybe not as fully there yet, as one might like. Racket also has lots of libraries. And even a standard library web framework.

So lets say I want to start my next web project in Janet. I already know Scheme and can probably quite easily just start writing another lisp, assuming it has TCO and I can do things mostly like I would in Scheme, except maybe for having to use funcall (which is annoying, but OK). Does Janet have libraries, that enable web projects? Like a web server and SXML or something like that? Or does it have things like a JSON parser? All these little things one would like to have, to not have to develop the basics first, before getting to the actual project.

And what about data structures? Are there functional data structures available? In GNU Guile I have at least the unmaintained guile-pfds. Hopefully, I will one day understand enough about functional data structures to build more or to maybe even maintain that library. But learning resources are scarce. It is already difficult to find a functional version of an AVL tree! Lots and lots of places merely teach non-persistent, non-functional versions of these data structures, and it is not trivial to translate them, might impact performance in ways that are not necessary, if one had great knowledge about how to make these data structures.

And also reproducibility! With GNU Guile I have what I need on Guix, which is great! With other languages, I might need to rely on older package managing approaches, that do not have reproducibility/determinism as the a high goal on their agenda, or might even lack the ability to create lock files/files with checksums. I don't want to go back to non-reproducible.

I am also eyeing statically typed variants like Carp. Same questions arise. Some seem really great and I would probably enjoy using them a lot. Would be a pity to then discover, that the ecosystem is just not there, and one has to create all the basic tools one needs oneself. Sometimes that can be fun, but it can also be exhausting and one never gets around to ones actual project.

veqq · a month ago
Janet has ~10 web frameworks (half SSG, half dynamic) and many web servers. Joy [0] is the most fully featured stack approach, which Janetdocs [1] runs on. But everything you mention is in the std lib. Here's a certbot in 10 lines only using the extended std lib (called spork): https://codeberg.org/veqq/janetdocs/src/branch/master/ssl-fe... `json/decode` automatically maps json to native data structures. There's a package manager included, which builds all code I've found so far, reproducibly.

As for DS, only arrays, there are maps, arrays and strings, all mutable or immutable. I don't think there's any intention to ever implement functional data structures, but they could "easily" be a library.

- [0] https://github.com/joy-framework/joy - [1] http://janetdocs.org/

zelphirkalt · a month ago
I see that there is a package manager "jpm" and I looked at the docs, but I couldn't see anything relating to how to create a lock file or how it makes sure, that every time I install dependencies, I get the exact same versions (not just version numbers).
przmk · a month ago
Are any of them maintained? I see that the last commit for Joy was 2 years ago.
veqq · a month ago
Here's a implementation of some persistent DS: https://github.com/ianthehenry/jimmy It's incomplete, primarily serving as a c++ interop example, though.
zelphirkalt · a month ago
That looks cool. I scrolled through the readme though and it only lists vectors, maps, and sets. That's not actually that much, but it is quite foundational. Maybe one could build others on top of that. But then the question arises, whether that implementation is performant.
mesaoptimizer · a month ago
Also see https://janet.guide/ for a good introductory book to Janet.
qart · a month ago
This is the first time I'm seeing the book. The author is solid! He has just the right sense of humour for a programming book.
Lyngbakr · a month ago
He works at Jane Street and was recently on their podcast§. An interesting chap, for sure!

§https://signalsandthreads.com/building-tools-for-traders/

dmpk2k · a month ago
Does it have a native compiler and/or types? Basically, can it get in the ballpark of SBCL's performance?

It'd be nice to have something cleaner than Common Lisp, and a much smaller image size. If it has decent performance too, I'm sold.

ethan_smith · a month ago
Janet uses a bytecode VM that's faster than many dynamic languages but won't match SBCL's native compilation performance; it has optional type annotations for documentation but not for optimization.
netbioserror · a month ago
It's a lightweight embeddable interpreter and runtime, similar to Lua. Dynamically and strongly typed, but no native compilation. Easy to call C libraries, or embed into C projects. In my testing, it's roughly twice as fast as Python for similar tasks. You can "compile" a project by embedding scripts and resources with the runtime into a bundled executable.
terminalbraid · a month ago
Janet does compile to standalone executables with jpm
xigoi · a month ago
Just keep in mind that these executables are the Janet bytecode interpreter bundled with your bytecode, not “real” native executables.
atemerev · a month ago
This is not a replacement for Common Lisp. It is in the same niche as Guile (but quite faster).
terminalbraid · a month ago
Yeah, I see Janet as "what Guile intended itself to be", though it is quite a bit smaller (in some ways that's a postive). I find the choices it made to be more pragmatic and it's far more accessible in non-linux environments since Guile tied itself closely to guix.
anthk · a month ago
Current Guile it's much faster.
rich_sasha · a month ago
Is there some kind of decision tree for "which lisp should i use?". CL, Scheme, Racket, Clojure, Janet... Elisp at least is clear :)
spauldo · a month ago
CL is like the C++ of the Lisp world. It's standardized, multiparadigm, has a ton of functionality, fast, and built with large codebases in mind. It's also got a lot of cruft and because the standard is old it lacks certain things people expect, like networking and threads. Implementations usually provide these and compatibility libraries do a decent job of smoothing over implementation differences. Choose CL if you have a team, a large project, and you need speed.

Scheme was written for educational purposes. It's very minimal, and implementations aren't very compatible for anything outside the spec and the SRFIs (specs for optional functionality). I'd you choose a major implementation like Guile or Chicken however, there are tons of libraries available and it's very usable for small and medium-sized projects. It isn't known for its speed. Choose Scheme if you think like a computer scientist.

I've never used the others enough to comment, although I did enjoy playing around with Clojure since it's a functional language. I'd do more with it if it wasn't tied to Java and JavaScript. I keep telling myself to learn some Racket, but I never have the time.

Personally, I do most of my Lisp work in elisp, since my regular job isn't Lisp-based but I need to mangle text a lot. elisp is from the same tradition as CL so it's pretty similar.

Y_Y · a month ago
Typical, asked for a tree and returns a flat list...
Zambyte · a month ago
They are about as different as C for Unix, C for Windows, C for microcontrollers, etc. They're all really the same language; the biggest differences are the available libraries. Just pick a Lisp and go for it! :)

If you're on a GNU system, I found GNU Guile to be exceptional to learn Lisp with. Particularly with following the SICP lectures from MIT (with Hal Ableson and Gerry Sussman). There are lots of great options though!

fredrikholm · a month ago
CL for performance and 'Lispiness'.

Scheme if you really enjoy recursion.

Clojure if you need the JVM and/or employment (this is me).

Racket if you drink the DSL kool aid.

Fennel (same author as Janet) for Lispy Lua.

Janet for Lispy C.

bjoli · a month ago
Is there anything that is janet-unique? I just did a cursory glance, and most of it seems like a scheme with slightly different syntax and a more "modern" standard library.

Why should I switch from my scheme of choice (guile) to Janet?

veqq · a month ago
It's not a Scheme at all! It doesn't have cons cells after all. It's a Clojure-like (maps everywhere, collection api, immutable data structures) with 1mb executable and [servers](http://janetdocs.org/) running under 10mb of ram.

Fibers are very interesting, even used for error handling. I've not wrapped my head around PEGs yet.

bjoli · a month ago
That makes sense. I have always thought about what I would do if I could make a "modern scheme". A lot would be taken from clojure but definitely not everything. Cons cells would stay, but the star of the show would be immutable vectors based on rrb trees or maybe finger trees (efficient concatenation, insertion in the middle etc), HAMTs , concurrentML (like guile-fibers) and a nice looping facility (like my own goof-loop[1]) and restricted mutation. Syntax-case and syntax-parse from racket. An extensible pattern matcher (like the one found in racket).

I would also make strings immutable, maybe like Guile's cow-strings, maybe blobs-with-cursors.

Definitely just copy Guile's delimited continuations.

I think I would just ignore most of r7rs, since I don't think it improves things for the progrmmer.

girvo · a month ago
PEGs (even outside Janet) are amazing and what I reach for all the time :) definitely one of those tools that’s worth learning!
ggm · a month ago
If a language lacks cons can it truly be held to be a lisp or has heresy taken over?
worthless-trash · a month ago
Thank you for janetdocs.org , I hated having the missing functions from janetdocs.com
3036e4 · a month ago
I did most of the 2023 Advent of Code using Janet and it was a great experience. I forced myself to use PEGs as much as possible, even when it was overkill, and I really began to like those for the readability and ease compared to other parsers/regexps that I have used.

I like that it is a small language without dependencies. Have it installed everywhere, including in termux on my phone. Good for scripting.

Used to daydream about a native Clojure and Janet is close enough to that. Does not have everything, but the cost in size and dependencies is so much lower. It is simpler and easier and runs well even on a RPi Zero.

apodik · a month ago
A native clojure? have you seen jank?

https://jank-lang.org/

asQuirreL · a month ago
I would tend to use Janet for scripts, especially ones that need to talk to the outside world because of its fast startup and batteries included standard library (particularly for messing with JSON, making HTTPS requests, parsing with PEGs, storing data in maps), while I would use guile for larger projects where things like modularity, performance, or metaprogramming were more important to me.

That being said, these days I use Clojure for both (I use babashka to run scripts: https://babashka.org/)

worthless-trash · a month ago
I don't know enough about guile, but janet was pretty easy to develop for .

Its binaries are quite small, could wrap and embed raylib and a few small c libraries with no hassle. This makes distribution much easier.

For my simple 2d game jaylib (raylib) code.

  ls -laoh build/app
  -rwxr-xr-x  1 worthless   2.8M 27 Jul 17:28 build/app

  otool -L ./build/app
  ./build/app:
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1356.0.0)
        /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 24.0.0)
        /System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo (compatibility version 1.2.0, current version 706.41.0)
        /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
        /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
        /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 2674.3.0)
        /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 4034.0.0)
        /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics (compatibility version 64.0.0, current version 1951.0.4)
        /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1226.0.0)
        /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 4034.0.0)
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
I believe those are pretty standard to have on most OSX machines, the situation is similar for my Linux system.

The LLM's really can't deal with janet though, they seem to think its clojure and screw up a lot of things.

johnisgood · a month ago
Feed your LLMs the documentation and example code (perhaps the whole stdlib if it fits). Tell your LLM that it is not Clojure nor Scheme, it is a different language. I have worked with more niche languages than Janet with Claude before this way, successfully.
terminalbraid · a month ago
One big difference is you can compile Janet programs down to executables without any additional dependencies or runtimes. It makes distribution extremely nice. The ffi is also much easier.
atemerev · a month ago
If you are happy with Guile, I guess Janet is not worth switching (it is faster, though). It is absolutely and explicitly not Scheme, though. More like natively compiled and script-optimized Clojure.
xigoi · a month ago
One thing I really like about Janet, compared to Scheme, is that it’s one language instead of a family of similar but incompatible languages.
NeutralForest · a month ago
Janet is awesome but pretty please, work on the tooling. There's very little in the way of working and debugging interactively with the REPL from any IDE that I know of and last time I tried (on Emacs) there was barely a dedicated mode to work with it.
NeutralForest · a month ago
Since other people mentioned there's been work there, here is my Emacs config now:

  (use-package janet-ts-mode
    :ensure t
    :defer t
    :vc (:url "https://github.com/sogaiu/janet-ts-mode"
            :rev :newest))

  (use-package ajrepl
    :ensure t
    :defer t
    :vc (:url "https://github.com/sogaiu/ajrepl"
            :rev :newest)
    :hook (janet-ts-mode . ajrepl-interaction-mode))
Also, a fix for treesit auto to not ask for the grammar every time:

  (use-package treesit-auto
    :pin melpa
    :ensure t
    :custom
    (treesit-auto-install 'prompt)
    :config
    (add-to-list 'treesit-load-name-override-list
               '(janet "libtree-sitter-janet-simple" "tree_sitter_janet_simple"))
    (add-to-list 'treesit-language-source-alist
             '(janet-simple . ("https://github.com/sogaiu/tree-sitter-janet-simple")))  
    (treesit-auto-add-to-auto-mode-alist 'all)
    (global-treesit-auto-mode))

terminalbraid · a month ago
Janet is also supported by conjure in neovim

https://github.com/Olical/conjure

The LSP for it works reasonably well.

packetlost · a month ago
I've also added Janet support to nvim-paredit [0] and use a combination of that, conjure [1], and nvim-parinfer to get a really slick editing experience in neovim.

[0]: https://github.com/julienvincent/nvim-paredit

[1]: https://github.com/julienvincent/nvim-paredit

[2]: https://github.com/olical/conjure

chubot · a month ago
Have you tried contributing any tools?
worthless-trash · a month ago
I use janet ts mode in emacs and Ajsc netrepl integration, for at least a while now.

You should try again.

NeutralForest · a month ago
I've been trying to use ajrepl but as mentioned in the README, there's a lot of cruft that gets output. How do you setup ajsc?

Deleted Comment