Readit News logoReadit News
ianthehenry · 3 years ago
Oh hey! Nice to see this on the front page here. I love Janet -- I've been using it for about year and a half, and it's now my go-to scripting language when I need something more powerful than bash, or when I want to hack on goofy little side project (some examples in my profile).

Parsing expression grammars (think, like, declarative parser combinators?) are a really great feature for ad-hoc text parsing -- and nicer than regular expressions, in my opinion, for anything longer than about ten characters.

The language itself is also a great introductory language-with-lots-of-parentheses, so you can explore compile-time metaprogramming with familiar runtime semantics -- think JavaScript plus value types minus all the wats. The embeddability and easy distribution (compiles to a static binary on any platform) is a huge plus as well.

Honestly I like Janet so much that I'm writing a book about it, because I think it's a shame that the language isn't more well-known. It's great! You should check it out right now!

weavie · 3 years ago
Is there somewhere I can keep up to date with books progress?
ianthehenry · 3 years ago
I'll announce it on my RSS feed/newsletter/twitter once it's done, if you use any of those. I'd estimate that it'll be out by the end of March; I won't write any public updates until it's ready for people to read.

Deleted Comment

mike_hock · 3 years ago
I went there, saw the Lisp syntax, and noped back out.
camdez · 3 years ago
Agreed.

This is why I don't do any math I can't do on my fingers.

Parentheses are just too scary, and there's no way that parenthesis math junk actually has any useful ideas.

pmoriarty · 3 years ago
Lisp syntax is a huge plus for me, and if a language doesn't have it I know it's not for me.
sergiotapia · 3 years ago
Same reaction here... wow that is a rough looking language. Then again I always disliked those kinds of languages like Clojure. The syntax is just too much for me. I feel like if I used it, it would atrophy my skills in other more traditional languages.
dunefox · 3 years ago
Your loss.
malodyets · 3 years ago
Nope as a verb is new to me - just heard it for the second time this week. First time was from my child.
co_dh · 3 years ago
Me too
pmoriarty · 3 years ago
I love Lisp (particularly Scheme), and heard that Janet was strongly inspired by Lisp and is "really Lisp underneath", but is really fast and strong at math, so I thought I'd give it a try, and after learning it I started wondering to myself, "why am I not simply using Lisp?"

Though arguably lispy, Janet just wasn't lispy enough for me. It was missing the simple, elegant sexp syntax I dearly loved, and I started to wonder what huge win I was getting from using it instead of just using Lisp or Scheme? Having not found a good answer, I did just that.

That was the last time I bothered trying to learn a "Lisp-like" language that wasn't actually a Lisp, and decided to just stick to Lisp/Scheme. They do everything I need, are good at math, and are plenty fast enough for me.

dri_ft · 3 years ago
>It was missing the simple, elegant sexp syntax I dearly love

In what sense does Janet not have sexp syntax? Seems plenty sexpy to me. Purists seem to say it's not a lisp because its underlying data structure is not (cons-based) lists as in classical lisp, but I don't see what syntactic difference there is.

ravi-delia · 3 years ago
Op was understandably confusing Janet with Julia
joaogui1 · 3 years ago
Uhm, sorry for asking, but are you sure you're not mistaking Janet and Julia?
pmoriarty · 3 years ago
Oops.. I think you're right.. It was Julia, not Janet... now I feel like an idiot, and apologize for my uncalled-for, unfair, and undeserved mischaracterization of Janet, a language I never tried.

I wish I could take it back, but HN won't let me delete my post. I apologize. Mea culpa.

progre · 3 years ago
I think its a pretty nice language.

Those extra bits of syntax that makes it "not a lisp" are mostly around defining "not list" kind if data structures. I find it practical.

lispm · 3 years ago
Lisp usually has a lot of non-list data structures like arrays. records, strings, classes/objects, hashtables, ... For some data structures there is built-in syntax and with an extensible reader (the extensible parser for s-expressions) the user can add additional syntax. Janet uses a non-extensible parser for the data syntax.

What Janet makes a 'not really a Lisp' is that "LISP" stands for "List Processor". Janet isn't exactly that, since it is not using linked lists as a core data structure - unlike Lisp where its List Processing features are built on top of linked lists made of cons cells.

(1 2 3) is called a "tuple" in Janet and represents something like an immutable array.

cosmojg · 3 years ago
What data structure isn't just a list with extra steps?
ravi-delia · 3 years ago
Op was thinking of Julia
nine_k · 3 years ago
The list of features available out if the box is pretty impressive, especially if you are scripting something concurrent. I would tolerate the syntax quirks in exchange for that.

Or maybe your particular Scheme has all of that out of the box, too. Which one do you normally use, if you don't mind?

ravi-delia · 3 years ago
Op was thinking of Julia
crabbone · 3 years ago
One thing that bothers me about languages that compose functions like this f(g(x)) is that when programming interactively f is typically an afterthought. So, you start out with g(x) and then need to go all the way back and add f. Similarly, when x turns out like it needs to be elaborated, and you either have to go all the way back, or edit the expression in place making it longer and inevitably facing problems with terminal length and terminal input being determined by when you press "Enter".

I like Lisp languages, and would take Scheme over Python for my job in a heartbeat, if I was allowed to. But, I think, that if we want interactive Shell-like programming, we really need to address the issues above in the language. Shell pipes are a good start, but they are quite restricted in what they can do and require xargs "extension". Some languages also have the "where" form, where arguments to a function can be elaborated after the function call.

If I was ever to design a language for interactive programming, I'd certainly try to have these two features in it.

adrianmsmith · 3 years ago
> So, you start out with g(x) and then need to go all the way back and add f.

That's one thing I will say after coming from Perl/PHP to Java, is that despite its verbosity and the uselessness of having to write .stream(), I much prefer Java's stream.map(...).filter(...) syntax over the more functional-style filter(map(list, ..), ..) syntax. The Java syntax reads left-to-right, which is the order you want when you're thinking about code, and also as you say writing it. I think if I were creating a programming language I too would try to make stuff read left-to-right as much as possible.

mst · 3 years ago
It's notable that raku (previously known as perl6) lets you write things in either direction, if I remember correctly something like

  @source >>> map { ... } >>> grep { ... } >>> my @sink;
though note I'm typing from memory on my second coffee so I may have got that slightly wrong.

Plus of course there's many languages with a |> operator so you can do

  g(x) |> f
I also (the example is specialised for I/O but the implementation technique could trivially be borrowed for something that wasn't) implemented something sort of in this direction for perl once: http://p3rl.org/IO::Pipeline

I'm not convinced that left-to-right is -always- the best option and prefer having the choice of both, but I wouldn't be at all surprised if a survey of developers found that if they could only pick one they'd pick left-to-right, and while I'd find it hard to choose for myself alone I'd probably pick left-to-right on the basis that it'd likely make it easier to onboard people to any given codebase.

ocimbote · 3 years ago
Aligning reading order with flow of actions is so important!

That's why I use and msybe tend to abuse the `->` and `->>` macros in Clojure and the pipe operator `|>` in Elixir.

Hopefully soon in JS as well, if I've read correctly.

temporallobe · 3 years ago
Not sure about other Lisp languages, but Clojure has thread operators that allow you to compose function calls this way, allowing you to visualize code in that preferred left-to-right (or top-to-bottom) order.
nordsieck · 3 years ago
In addition to the examples other people have given, I think Ruby does this very nicely by making map, filter, and reduce methods on collection data structures.

Of course, Ruby is a bit of a mixed bag, but for the applications where it fits, it can be very nice.

ianthehenry · 3 years ago
Thank you for making an actually relevant point about syntax. I agree with this 100%, and I love Janet, and was recently doing a lot of interactive Janet programming for a generative art playground.

So I added postfix function application. So instead of (f (g x)), you can write (g x | f).

I liked the syntax a lot, but it looked really weird with operators: (calculate x | + 1). So I made operators automatically infix: (calculate x + 1).

I also didn't like that the transformation from foo to (foo :something) (record field access) required going back and adding parentheses before the value, so I added foo.something syntax that means the same thing.

The result is something that's very easy for me to type and read:

    (def eyes
      (eye-shapes
      | color (c + 0.5)
      | color (c - (dot normal (normalize eye-target) - 0.72
              | clamp -1 0
              | step 0))
      | color [c.b c.g c.r]))
(Excerpt from the logo of https://toodle.studio -- https://gist.github.com/ianthehenry/612c980f0db04ea3c2ccab27...)

Is this even Janet anymore? I dunno. It's a Janet dialect, and it's implemented as regular old Janet macros. But it's much easier for me to type like this. I recognize that it makes my code necessarily single-player, but that's fine for the sorts of dumb projects that I do for fun.

I think a lot of lisp programmers use paredit exactly so that they can write (f (g x)) in the order g x f, but with their editor re-positioning their cursor and taking care of paren-wrapping automatically. But I don't use paredit, and I don't want to wed myself to a particular mode of editing anyway. So I like a syntax that lets me type in the order that I think.

lispm · 3 years ago
The 'terminal' restriction is long gone. Most Lisp read-eval-print-loops run inside an editor or another specialized tool.

In Common Lisp:

  CL-USER 37 > (sin 3)
  0.14112

  CL-USER 38 > (cos *)
  0.9900591
Above really is (cos (sin 3)). The variable * is bound to the last result.

crabbone · 3 years ago
How'd you go about multiple-value-bind? Same problem with handler-case.

When used interactively, Python also has _ to store the previous value (but Python only ever really returns single value, which is sometimes a tuple or a list that can be deconstructed into variables, iirc in CL if you don't request other return values, they are gone.)

More generally, you'd want more of xargs-like functionality (eg. split result into chunks and feed them to the next function in chunks, perhaps in parallel). Or maybe you'd want something like a tee, to split the results of the previous function into multiple streams and processed by different functions? Java-like languages don't immediately support something like that, but Shell-like do with redirection syntax, tee, xargs.

bo-tato · 3 years ago
you're totally right that it's often easier to read in the order the functions are being applied. That's why just about every lisp/scheme family language has thread-first and thread-last macros -> and ->> so f(g(h(x))) could be written as: (-> x h g f) Janet, clojure and racket and probably others have them built in, emacs lisp has it in dash.el, common lisp has it in cl-arrows and other libraries

It's really just about readability preference though not ease of editing, lisp like languages will have paredit/sexp editing shortcuts in your editor, so when you're on (f x), you press one key and it's turned into (<cursor here> (f x))

camdez · 3 years ago
Emacs Lisp actually has threading macros natively (seemingly since at least 2016), but they're (IMHO) obnoxiously named `thread-first` and `thread-last`.
tincholio · 3 years ago
I'm not familiar with Janet, but I know it's Clojure-inspired, so it probably has threading macros, which are like shell pipes on steroids. In practice, when doing REPL-based development, it's very common to use these as opposed to (g(f x)).
turbohz · 3 years ago
Janet does indeed have those.
twism · 3 years ago
Maybe what you are looking for is threading https://stuartsierra.com/2018/07/06/threading-with-style
tsujp · 3 years ago
dang · 3 years ago
Thanks! Macroexpanded:

Show HN: Make 3D art in your browser using Lisp and math - https://news.ycombinator.com/item?id=32738654 - Sept 2022 (38 comments)

Janet – a Lisp-like functional, imperative programming language - https://news.ycombinator.com/item?id=28850861 - Oct 2021 (135 comments)

Janet Programming Language - https://news.ycombinator.com/item?id=28255116 - Aug 2021 (114 comments)

Janet: a lightweight, expressive and modern Lisp - https://news.ycombinator.com/item?id=23164614 - May 2020 (269 comments)

Janet – A dynamic language and bytecode VM - https://news.ycombinator.com/item?id=19179963 - Feb 2019 (50 comments)

Janet, a Clojure inspired language for scripting, or embedding in other programs - https://news.ycombinator.com/item?id=19172510 - Feb 2019 (1 comment)

Janet, a bytecode Lisp vm - https://news.ycombinator.com/item?id=18759277 - Dec 2018 (1 comment)

cfiggers · 3 years ago
Janet is really powerful. Here's a small TUI text editor I'm writing in it, if you want to see a non-trivial example: https://www.github.com/CFiggers/joule-editor
DennisP · 3 years ago
Ooh, nice. I've been messing around with a weird text editor that started with that same tutorial, but in Nim. Janet is intriguing, I'll be digging into your code.

How was the debugging experience?

cfiggers · 3 years ago
> I'll be digging into your code.

My apologies in advance, then! (Ha.) The "main" function is at the very bottom of src/joule.janet. So I'd recommend starting there.

As for debugging, Janet embraces REPL-driven development, so the debugging experience is all about setting up, interactively querying, and step-wise updating your program's state, live in memory, using the REPL. It's quite a bit different from a lot of languages—not better, intrinsically, just different. But I like it a lot.

Is your Nim editor public anywhere? I've heard a lot of good things about Nim and wouldn't mind exploring a real-world example.

BWStearns · 3 years ago
Thought the link was broke but GH looks broken now?

Edit: Back up now

iainctduncan · 3 years ago
If you like things like Janet, you might also like s7 Scheme. It is also a minimal Scheme built entirely in C and dead easy to embed. I used it to make Scheme for Max and Scheme for Pd, extensions to the Max and Pd computer music platform to allow scripting them in Scheme. (https://github.com/iainctduncan/scheme-for-max) Janet was one of the options I looked pretty closely at before choosing s7.

The author (Bill Schottstaedt, Stanford CCRMA) is not too interested in making pretty web pages, ha, but the language is great! https://ccrma.stanford.edu/software/snd/snd/s7.html

BWStearns · 3 years ago
So this is kind of like a lightweight non-jvm clojure? I like it. Looks like it could be a nice swiss army knife for data munging.
haspok · 3 years ago
You mean Python, not Clojure. A number of key underpinnings, such as (almost) exclusively immutable datastructures are missing from this language.

It is more of a Python with a LISP syntax.

dgb23 · 3 years ago
If anything it’s major inspirations seem to be Clojure and Lua.

It has some of the affordances of the former in terms of semantics, but is stripped down and friendly like Lua.

The use cases also seem to overlap with Lua, as a fast, embeddable scripting language that you can easily keep in your head (see docs).

It seems to be simpler than Lua because it doesn’t complect arrays and dicts into tables, as arrays are a separate construct. And it affords you with immutable versions of those.

To me it looks like a Clojure-like for Lua use cases.

SyrupThinker · 3 years ago
I'm pretty sure GP meant Closure, considering the language has matching immutable data structures for mutable ones [^1] and even its own (limited) version of EDN called JDN. It’s definitely also inspired by it.

[^1]: https://janet-lang.org/docs/data_structures/index.html

jacknews · 3 years ago
Or python with clojure syntax?

The author also wrote fennel, a lisp/clojure-ish wrapper for lua, so I think that's the influence.

BWStearns · 3 years ago
I meant Clojure. Janet's "more default looking" data structures are the immutable ones which is a pretty strong nudge. I don't see any explicit callout about data sharing for Janet but if that's really all that's missing I still feel good about citing Clojure first.
jimbo9991 · 3 years ago
This is really cool, surprised it has so few stars and I've never seen it talked about here. I like the LISPs but I've always thought not having a CPython type thing was a bit of a deal breaker for making it a go-to "primary" language that I would use everyday.

I'm definitely going to try with Janet though.

masklinn · 3 years ago
> I've always thought not having a CPython type thing

What cpython type thing? Do you mean a rich(er) set of built-in datatypes?

Because lots of lisps have that, some (e.g. clojure) also have reader macros for pseudo-literals.

Even Scheme has had a built-in hashmap since R6RS (2007), and R5RS implementations usually provided hashmaps even if they were not spec-defined. Common Lisp has had a hashmap more or less all along (at least since before ANSI standardisation)

iLoveOncall · 3 years ago
> surprised it has so few stars and I've never seen it talked about here

Why? It's a niche language in a dated syntax, with use cases already covered by other languages.

You will downvote because you don't like that, but it doesn't make it less true.

xigoi · 3 years ago
How is the syntax dated? I'd argue that S-expressions are timeless.