HI version is available. Content is displayed in original English for accuracy.
To create the design, I had AI analyze the ASTs of several mainstream languages plus a few of the conceptually groundbreaking but esoteric ones (listed in the README) and then create a new structure and new syntax. It was named after the Jacquard machine (https://en.wikipedia.org/wiki/Jacquard_machine), a precursor to Babbage's Analytical Engine (and punch cards).
The result reused a lot of existing ideas but combined them in what I found to be an interesting way. External/world effects are visible in function signatures, and the runtime requires explicit permission to touch the filesystem, network, etc. Effect interactions can be recorded and replayed to see what happens under different conditions or code. And since code is given a content-addressed semantic identity internally, renames and formatting changes don't require recompile or retesting.
Another piece that fell out of this was a testing framework called Warp, which combines replay, results caching, handler substitution, and a few other tools that I frankly wish I had when writing Python. There are a few examples available in the demos directory.
There's more to do, but it's installable and usable. I'm hoping people will have their agents digest the docs/SKILL.md file and maybe write a few programs or see where it might fit in their projects. It should be particularly useful in agent systems. If an agent says something is painful or you as a human find the code tough to understand, I'd like to hear about it so I can address it.
More detail here:
Repository: https://github.com/jbwinters/jacquard-lang
Further intro/human-oriented write-up here: https://research.friendmachine.co/jacquard/

Discussion (32 Comments)Read Original on HackerNews
Brilliant. I think Jai has something like that? Each function declares what it's going to touch (both read/write) globally, and I think you can specify that per block even.
I haven't used Jai (I think it's not out yet) but I remember the author talking about this and it sounded like a great idea.
It's related to the idea of pure functions being easy to reason about. Right now most languages don't even have a concept of pure functions, but the ones that do, just have two categories. When a function is messing with global state you do actually want to know what it's doing.
I think that can be statically computed (and displayed as IDE annotations or whatever) but specifying it explicitly sounds like a good practice either way.
I like that you're including other side effects (e.g. network) there too though, that's pretty cool!
Another thing I'm really interested in is proofs. Not necessarily total proofs (though we seem to be moving in that direction, at least for subsets of the codebase), but just normalizing rudimentary pre and post conditions checks.
I was thinking of setting it up so code can't even compile in release mode if those are missing. (Not every function would need them, but you at least want to state their absence explicitly.)
I was also thinking of setting up strictness levels per function, using hashing or something, so if a function is modified, you'd have to go through a process of double checking it again. And then functions labeled e.g. level 7 strict couldn't call ones with a lower proven strictness level, and so on. I'm told that I've basically been reinventing Ada from first principles so I should probably go and take a look at that...
Wait, your thing is doing hashing too... Woah. (I think that comes from proofs land or something?)
Yes, Jacquard uses content-addressed definitions and it should be possible to set up a process for 'review again if this changes' on top of it. Warp, the testing framework, already uses this to avoid rerunning pure tests when neither the definition or dependencies have changed.
Jacquard does not currently implement proof or strictness levels, but binding those to a definition’s content identity is interesting and definitely worth exploring.
What are you building that people keep comparing to Ada?
(In a nutshell: the more dynamic a programming language is, the more impossible it becomes to reason about what the program is doing. That's fine for throwaway scripts and game jams (#pragma JamMode), but the "the program is probably seriously wrong" should be explicitly opt-in, not the default ...)
So my current approach is everything should be as local as possible, as immutable as possible, etc. Basically Rust except I'm not a fan of low level programming. (I basically want Rust With GC (C# memory model), which sends Rust folks into paroxysms!)
I want it stricter than Rust in many respects, but also less annoying. (Better ergonomics and higher level, with a low level escape hatch when needed.)
Swift is apparently close to that, and might deserve another look.
I've also been obsessed with formal verification and proofs except, today I had a very revealing experience. I had an LLM incorrectly implement a major feature, and "verify" it with several thousand lines of tests. It was, as implemented, backwards, and also completely pointless — but all tests came back green!
I laughed when I realized, if it had been done in Rust, and with a layer of formal verification... well all the proofs (of the stupid and wrong and backwards thing) would have come back green too... It would have mathematically proven that the incorrect thing was correct...
> Algebraic effects with deep, multi-shot handlers. A handler can resume a computation zero, one, or many times, which is what makes exhaustive search and exact inference ordinary library code.
I love me some algebraic effects, but this sets off alarm bells for me.
Multi-shot effects are neat and powerful but are incredibly difficult to reason about for humans, and given that there are few languages that have implemented them (and they're so niche with very little training data) I'm skeptical that LLMs are sufficiently better at them to make up the gap.
One-shot effects are a cross between `throw` and a function call. Multi-shot are full-on delimited continuations and come with all the complexity that entails.
I had a very similar thought and ended up building a capability system[1] in my language to capture side effects.
[1] https://march-lang.org/docs/cookbook/capabilities/ * docs are a work in progress
> and the runtime requires explicit permission to touch the filesystem, network, etc
This feels like more of an OS problem (or library problem) than a language problem.
> Run one program against many worlds. The same code can run against the real network, a scripted fake, a recording of last week's traffic, or a probability model of how servers usually behave
How is the "world" model different from plain dependency injection?
In addition to what the other comment said, this "world" model is great for hermetic testing of complex code, LLM written or not. We've seen existing projects that intercept the OS level syscall for testing, replayability, etc. Building it into the language runtime, hopefully with better ergonomics from the start than a syscall, would be a welcome addition broadly.
Yeah agree, what I really want to see now, is a programming language for LLMs, designed by a human (although code could still be LLM-made I suppose), and see how both of them fare in various scenarios.
But basically world is a bit more narrow, that moment where your code touches the outside world (logging, http, etc), you can swap that. It's sorta like DI but deliberately narrower, only the moments where code touches the outside world are swappable.. With DI in theory you can replace anything, which has its benefits, but at least personally I am not a big fan of mocks, except when they touch the outside world. So that's what's replaceable.
Fricking training distribution/same-y ness coming for us all… cool project though.
it would make it easy for humans to easily stub out tests with a docstring description and the tests that would guarantee certain behaviors. for the machine, it'd make it easy to add in new tests because the function+tests are in the same context window
Given how many useless unit tests Codex just loves to write, no, thank you.
Thankfully, its training data completely misses this. So at least for now it completely ignores doctests (at least in Elixir).
Anything we make gets to participate in this evolutionary process, even if it sounded dumb at the outset. In fact, doing dumb things is how we get "unstuck" from outdated ways of thinking.
Building something like haskel's hoogle seems like a smart approach to this problem.
https://github.com/jbwinters/jacquard-lang/blob/main/docs/SK...
Agents I've tested with have had been able to pick up the language from that, at least to the extent that I've been able to test so far.
Whats different to the effects system just being a type system?
Isnt a function that opens a particular file still just a type? Perhaps dependent?
Reminds me of mercury which has determinism of the function like type signatures.
The effect system here is part of a type system (technically a type-and-effect system). Where a value type typically describes what value a computation returns, an effect describes which operations it can perform during evaluation.
The difference is that effects propagate through the call graph, so lower-level code cannot access disallowed resources without that authority appearing higher up. At runtime, world effects also require an explicit grant. In a typical value-type system, lower-level code can introduce side effects without them appearing in the caller’s type.