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.
Keel benchmarks



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 logo 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 logo 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 logo 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);
}