A fast, statically-typed interpreted language that aims to combine Rust-like syntax with Python's ease-of-use.
Install Keel
Run the following command in your terminal
Download .zip from GitHub releases
Try Keel in your browser
With WASM
Open the Keel playground
Why Keel?
Fast.
Keel is ~2-10x faster than Python, and competitive with LuaJIT (-joff), with aggressive compile-time optimizations.
Familiar syntax.
Rust-like, with Python's ease-of-use.fn fib(n: usize) -> usize {
if n <= 1 {
return n;
} else {
return fib(n - 1) + fib(n - 2);
}
}
fn fib_loop(n: usize) {
let mut results: Vec<usize> = Vec::new();
for _ in 0..n {
let fib_25 = fib(25);
println!("fib(25) = {}", fib_25);
results.push(fib_25);
}
println!("{:?}", results);
}
fn main() {
println!("Hello, World!");
fib_loop(25);
}
Rust
function fib(n) {
if n <= 1 {
return n;
} else {
return fib(n - 1) + fib(n - 2);
}
}
function fib_loop(n) {
let results = [];
for _ in 0..n {
let fib_25 = fib(25);
print("fib(25) = " + str(fib_25));
results.push(fib_25);
}
print(results);
}
function main() {
print("Hello, World!");
fib_loop(25);
}
Keel
def fib(n):
if n <= 1:
return n
else:
return fib(n - 1) + fib(n - 2)
def fib_loop(n):
results = []
for _ in range(n):
fib_25 = fib(25)
print("fib(25) = " + str(fib_25))
results.append(fib_25)
print(results)
print("Hello, World!")
fib_loop(25)
Python
Statically typed, zero annotations.
Supports full type inference, static type checking, and polymorphism.function add(a, b) {
return a + b;
}
function main() {
print(add(1, 2)); // 3
print(add(1.5, 2.5)); // 4.0
print(add("a", "b")); // "ab"
}
OUTPUT:
3
4
ab
function main() {
let numbers = [1, 2, 3];
numbers.push("four");
}
OUTPUT: KEEL ERROR Error: ╭─[ test.kl:3:18 ] │ 3 │ numbers.push("four"); │ ───┬── │ ╰──── Expected type Integer, │ found String ───╯
FFI support.
Call C/dynamic libraries directly from Keel.
int sum_int_array(int *arr, int len) {
int sum = 0;
for (int i = 0; i < len; i++) {
sum += arr[i];
}
return sum;
}
my_lib.c (compiled into my_lib.dylib on macOS)
// If the extension is omitted, Keel will choose the
// correct extension based on your OS.
import "my_lib" {
int sum_int_array(int[], int);
}
function main() {
let x = [0,1,2];
print(test::sum_int_array(x, x.len()));
}
test.kl
Language tour
// You can import other '.kl' files with this syntax.
// All top-level functions from the imported file become available immediately.
// Imports can be nested, but circular imports trigger an error.
use "my_lib.kl"
// You can load functions from dynamic libraries by specifying each function's signature
// If the extension is omitted, Keel will choose the correct extension based on your OS.
// On macOS, it will try to load "test_lib.dylib".
// On Windows, it will try to load "test_lib.dll".
// On Linux, it will try to load "test_lib.so".
import "test_lib" {
int add(int, int);
float add(float, float);
string add(string, string);
// Specify arrays with type[]
int sum(int[], int);
}
// The main function is required.
// It's the entry point of your program.
function main() {
// Variables are declared with 'let name = value'
// Keel has 5 built-in types:
let int_var = 42;
let str_var = "Keel";
let float_var = 3.14;
let bool_var = true;
let array_var = [1,2,3,4,5,6];
// Arrays are homogeneous and can only hold one type
let nums = [3,1,4,1,5,9];
nums.sort();
print(nums[0]); // 1
print(nums.len()); // 6
print(nums.contains(9)); // true
nums.push(2);
nums.remove(0); // Removes the first element
// You can obtain slices of collections (arrays and strings):
let nums = [3, 1, 4, 1, 5, 9];
print(nums[..2]); // [3,1]
print(nums[0..2]); // [3,1]
print(nums[2..4]); // [4,1]
let msg = "Hello world";
print(msg[..5]); // "Hello"
print(msg[0..5]); // "Hello"
print(msg[6..11]); // "world"
// All blocks are anonymous namespace scopes
// Trying to access x outside of this block would yield an error
{
let x = 42;
print(x);
}
let x = 20;
if x == 20 {
print("20!");
} else if (x == 15) { // Parentheses are optional
print("15!");
} else {
print("It's something else!");
}
// Inline conditions work as expressions
let my_number = 42;
let the_answer = if my_number == 42 { "It's the answer!" } else { "It's not the answer..." };
print(the_answer);
let i = 0;
while i < 10 {
print(i);
i += 1;
}
// Using _ as the variable name in a for loop will discard the value,
// making the program faster, but preventing access to the element
for x in [0,1,2,3] {
for _ in "abcd" {
print(x);
}
}
// Use 'break' to exit the loop.
// Use 'continue' to skip to the next iteration.
let i = 0;
while i < 10 {
i += 1;
if i == 5 {break;}
continue;
print(i); // This is never run
}
// This is an infinite loop
// It loops indefinitely until flow is stopped
let i = 0;
loop {
i += 1;
if i == 10 {
break;
}
}
// This loops over a range of integers
for i in 0..10000000 { // Loops from i = 0 to i = 9999999
print(i);
}
// This is also valid
for i in ..10 { // Loops from i = 0 to i = 9
print(i);
}
let x = 0;
x = x + 1;
x += 1;
x = x - 1;
x -= 1;
x = x * 1;
x *= 1;
x = x / 1;
x /= 1;
x = x % 1;
x %= 1;
x = x ^ 1;
x ^= 1;
print(x == 1);
print(x != 1);
print(x > 1);
print(x >= 1);
print(x < 1);
print(x <= 1);
print(x > 1 || x < 1);
print(x > 1 && x < 1);
}