Like Forth, Snabl supports manipulating the parameter stack.
1 2 3 swap!
[1 3 2]
dup!
[1 3 2 2]
drop!
[1 3 2]
Snabl uses sigils to simplify local reasoning. Types start with uppcercase letters, variables are prefixed with @
, macros use !
or :
as suffix. Apart from literals; anything else is either a constant such as t
, f
and nil
; or a function.
{41 let: foo @foo ++}
[42]
Snabl provides strong, static, gradual, first class types. The root type T
may refer to anything except nil
.
42 I64?
[t]
I64 T?
[t]
42 Nil?
[f]
nil T?
[f]
Snabl borrows many ideas from functional languages; first class multi methods, pattern matching, lambdas, tail recursion and more. The following example implements a tail recursive fibonacci.
func: my-fib<I64 I64 I64> {
let: (n a b)
@n switch:,
0? @a
1? @b,
-- @b dup! @a + recall!
} 20 0 1 my-fib
[6765]
The same algorithm may be implemented anonymously in a single scope using a lambda with stack manipulation.
20 0 1 &(
rswap! switch:,
0? sdrop!
1? drop!,
-- rswap! dup! rot! + recall!
) call!
[6765]
Snabl supports cooperative multitasking using green threads, or tasks. By default, code runs in the main task. New tasks may be started using task:
.
task: (3 times:, 'pong say yield!)
3 times:, 'ping say yield!
ping
pong
ping
pong
ping
pong
[]
Snabl supports executing any calls that might hang asynchronously in a separate thread using async:
, await!
yields until the call returns and push any results.
foo.txt:
foo bar baz
''foo.txt'' r fopen
[(RFile 0x125b850)]
async: str
[(Async 0x126b550)]
await!
[''foo bar baz'']
Snabl offers two flavors of error handling, Maybe
and throw!
/catch
. Any value may be passed as Maybe
, stray nil
's are usually caught in the next function call.
func: foo<T> _
foo 42
[42]
nil foo
[nil]
Error in row 1, col 0:
'Func not applicable: foo'
func: bar<Maybe> _
42 bar
[42]
nil bar
[nil]
Any value may be thrown. try:
runs its argument and pushes an error or nil
on the stack, catch
may be used to retrieve the thrown value.
try: (41 throw!)
catch ++
[42]
Snabl integrates deeply into C++ and the STL, and is relatively trivial to embed.
Example 5
snabl::Env env;
env.home.add_fimp(
env.sym("my-fib"),
{snabl::Box(env.int_type)},
[&env](snabl::Fimp &fimp) {
snabl::Box &v(env.peek());
snabl::I64 n(v.as_i64), a(0), b(1);
while (n-- > 1) {
std::swap(a, b);
b += a;
}
v.as_i64 = b;
});
env.run("10 my-fib say");
Snabl requires a C++17-capable compiler and CMake to build.
$ git clone https://github.com/codr4life/snabl.git
$ cd snabl
$ mkdir build
$ cd build
$ cmake ..
$ sudo make install
$ snabl
Snabl v0.4.1
Press Return on empty line to eval.
1 2 +
[3]
MIT