Slap: Functional Concatenative Language... with a Borrow Checker?
sebastien
Very nice, it's good to see a fresh take on concatenative languages and see how today's expectations (performance, safety, expressiveness) can be met. Nice also that the implementation is small, it's very in line with the philosophy of this family of languages. Thanks for sharing :)
slightknack
This is really cool! I can see the inspiration from APL, K, etc -- any plans for multidimensional arrays? Could be fun in combination with the SDL bindings (draw cool things with little code).
I also like how you use 'system effects' to interact with the runtime; this approach is neat! Sometimes I wonder whether if, instead of linear types to represent resources, we should use effects instead. E.g. in Koka:
fun main() {
with open("data.txt", Read)
val line = read-line()
println("Got line: " ++ line)
}
In my old language Passerine, I also planned on using algebraic effects for system inferfaces -- I think I have an old blog post or something about it... hmm. Here's a github issue that mentions it in passing:
The [type system] should support Algebraic Effects. Interaction with the FFI [which includes the runtime] should be done through such handlers for effects.
I think an older version of an experimental language Pen is where I first came across the idea? Unclear.
For languages with a runtime I admit handing effects up the stack and reifying them at the runtime level if they are not handled is a very satisfying way to implement an FFI for a scripting language.
Returning to effects for references, I think I recall vaguely this proposal to add rank-2 polymorphism to koka in a way compatible with the effect system (perhaps it was this paper), which allowed you to e.g. define a memory effect. Adapting the syntax used in the paper, something like:
scoped effect mem<s::S> {
ctl malloc(size : int) : ptr<s>
ctl free(p : ptr<s>) : ()
}
named effect ptr<s::S> in mem<s> {
fun load(offset : int) : int
fun store(offset : int, value : int) : ()
}
(Note that here s is the heap, and not the type of the pointer reference.) This allows you to make some memory, and free the pointer only if the original effect is in scope!
surprisetalk
You should be able to do multi-dim arrays right now, but I don't think it'll ever support polymorphic rank ops like [[1 2 3]] [[4 5 6]] plus.
Yep, effects are great! My vague plan right now is to add a lightweight threading primitive and then rebuild all the filesystem apis to be essentially effects handlers with simple box handles. Stay tuned
Very cool! Thanks for sharing
jnb
I’m a bit surprised that the implementation is only 2k lines despite the repo having a claude.md file.
ficd
Given the length of the Claude file, it seems like the author is using the tool lightly. In sloppy repos the agent markdown files tend to be really long, half-defined specs. Claude is only credited on a few commits, and since the blog post doesn't have that AI smell, I get the sense the author understands it pretty well. That that said, I would love to know the reason for those strange commit messages...
jonathannen
I did use FORTH quite a bit back in my uni days, so it's always nice to see a concatenative language in the wild -- baseline this is pretty cool.
I do think the "borrow" comparison is a bit stretched. I can see where you’re coming from, but trying to map this onto a Rust lens felt more distracting than clarifying.
sebastien
Very nice, it's good to see a fresh take on concatenative languages and see how today's expectations (performance, safety, expressiveness) can be met. Nice also that the implementation is small, it's very in line with the philosophy of this family of languages. Thanks for sharing :)
slightknack
This is really cool! I can see the inspiration from APL, K, etc -- any plans for multidimensional arrays? Could be fun in combination with the SDL bindings (draw cool things with little code).
I also like how you use 'system effects' to interact with the runtime; this approach is neat! Sometimes I wonder whether if, instead of linear types to represent resources, we should use effects instead. E.g. in Koka:
fun main() {
with open("data.txt", Read)
val line = read-line()
println("Got line: " ++ line)
}
In my old language Passerine, I also planned on using algebraic effects for system inferfaces -- I think I have an old blog post or something about it... hmm. Here's a github issue that mentions it in passing:
The [type system] should support Algebraic Effects. Interaction with the FFI [which includes the runtime] should be done through such handlers for effects.
I think an older version of an experimental language Pen is where I first came across the idea? Unclear.
For languages with a runtime I admit handing effects up the stack and reifying them at the runtime level if they are not handled is a very satisfying way to implement an FFI for a scripting language.
Returning to effects for references, I think I recall vaguely this proposal to add rank-2 polymorphism to koka in a way compatible with the effect system (perhaps it was this paper), which allowed you to e.g. define a memory effect. Adapting the syntax used in the paper, something like:
scoped effect mem<s::S> {
ctl malloc(size : int) : ptr<s>
ctl free(p : ptr<s>) : ()
}
named effect ptr<s::S> in mem<s> {
fun load(offset : int) : int
fun store(offset : int, value : int) : ()
}
(Note that here s is the heap, and not the type of the pointer reference.) This allows you to make some memory, and free the pointer only if the original effect is in scope!
surprisetalk
You should be able to do multi-dim arrays right now, but I don't think it'll ever support polymorphic rank ops like [[1 2 3]] [[4 5 6]] plus.
Yep, effects are great! My vague plan right now is to add a lightweight threading primitive and then rebuild all the filesystem apis to be essentially effects handlers with simple box handles. Stay tuned
Very cool! Thanks for sharing
jnb
I’m a bit surprised that the implementation is only 2k lines despite the repo having a claude.md file.
ficd
Given the length of the Claude file, it seems like the author is using the tool lightly. In sloppy repos the agent markdown files tend to be really long, half-defined specs. Claude is only credited on a few commits, and since the blog post doesn't have that AI smell, I get the sense the author understands it pretty well. That that said, I would love to know the reason for those strange commit messages...
jonathannen
I did use FORTH quite a bit back in my uni days, so it's always nice to see a concatenative language in the wild -- baseline this is pretty cool.
I do think the "borrow" comparison is a bit stretched. I can see where you’re coming from, but trying to map this onto a Rust lens felt more distracting than clarifying.
Very nice, it's good to see a fresh take on concatenative languages and see how today's expectations (performance, safety, expressiveness) can be met. Nice also that the implementation is small, it's very in line with the philosophy of this family of languages. Thanks for sharing :)
This is really cool! I can see the inspiration from APL, K, etc -- any plans for multidimensional arrays? Could be fun in combination with the SDL bindings (draw cool things with little code).
I also like how you use 'system effects' to interact with the runtime; this approach is neat! Sometimes I wonder whether if, instead of linear types to represent resources, we should use effects instead. E.g. in Koka:
In my old language Passerine, I also planned on using algebraic effects for system inferfaces -- I think I have an old blog post or something about it... hmm. Here's a github issue that mentions it in passing:
I think an older version of an experimental language Pen is where I first came across the idea? Unclear.
For languages with a runtime I admit handing effects up the stack and reifying them at the runtime level if they are not handled is a very satisfying way to implement an FFI for a scripting language.
Returning to effects for references, I think I recall vaguely this proposal to add rank-2 polymorphism to koka in a way compatible with the effect system (perhaps it was this paper), which allowed you to e.g. define a memory effect. Adapting the syntax used in the paper, something like:
(Note that here
sis the heap, and not the type of the pointer reference.) This allows you tomakesome memory, and free the pointer only if the original effect is in scope![[1 2 3]] [[4 5 6]] plus.I’m a bit surprised that the implementation is only 2k lines despite the repo having a
claude.mdfile.Given the length of the Claude file, it seems like the author is using the tool lightly. In sloppy repos the agent markdown files tend to be really long, half-defined specs. Claude is only credited on a few commits, and since the blog post doesn't have that AI smell, I get the sense the author understands it pretty well. That that said, I would love to know the reason for those strange commit messages...
I did use FORTH quite a bit back in my uni days, so it's always nice to see a concatenative language in the wild -- baseline this is pretty cool.
I do think the "borrow" comparison is a bit stretched. I can see where you’re coming from, but trying to map this onto a Rust lens felt more distracting than clarifying.
Very nice, it's good to see a fresh take on concatenative languages and see how today's expectations (performance, safety, expressiveness) can be met. Nice also that the implementation is small, it's very in line with the philosophy of this family of languages. Thanks for sharing :)
This is really cool! I can see the inspiration from APL, K, etc -- any plans for multidimensional arrays? Could be fun in combination with the SDL bindings (draw cool things with little code).
I also like how you use 'system effects' to interact with the runtime; this approach is neat! Sometimes I wonder whether if, instead of linear types to represent resources, we should use effects instead. E.g. in Koka:
In my old language Passerine, I also planned on using algebraic effects for system inferfaces -- I think I have an old blog post or something about it... hmm. Here's a github issue that mentions it in passing:
I think an older version of an experimental language Pen is where I first came across the idea? Unclear.
For languages with a runtime I admit handing effects up the stack and reifying them at the runtime level if they are not handled is a very satisfying way to implement an FFI for a scripting language.
Returning to effects for references, I think I recall vaguely this proposal to add rank-2 polymorphism to koka in a way compatible with the effect system (perhaps it was this paper), which allowed you to e.g. define a memory effect. Adapting the syntax used in the paper, something like:
(Note that here
sis the heap, and not the type of the pointer reference.) This allows you tomakesome memory, and free the pointer only if the original effect is in scope![[1 2 3]] [[4 5 6]] plus.I’m a bit surprised that the implementation is only 2k lines despite the repo having a
claude.mdfile.Given the length of the Claude file, it seems like the author is using the tool lightly. In sloppy repos the agent markdown files tend to be really long, half-defined specs. Claude is only credited on a few commits, and since the blog post doesn't have that AI smell, I get the sense the author understands it pretty well. That that said, I would love to know the reason for those strange commit messages...
I did use FORTH quite a bit back in my uni days, so it's always nice to see a concatenative language in the wild -- baseline this is pretty cool.
I do think the "borrow" comparison is a bit stretched. I can see where you’re coming from, but trying to map this onto a Rust lens felt more distracting than clarifying.