samlang
A statically-typed, functional, and soundÂ
programming language with type inference.
Introduction
samlang is a statically-typed functional programming language designed and implemented by Sam Zhou. The language is still under development so the syntax and semantics may be changed at any time.
The language can be compiled down to WebAssembly with reference counting based garbage collection.
Getting Started
Download the latest release from GitHub Releases. To start a new project, create a json file sconfig.json
with content {}
.
Notable Examples
Hello World
class HelloWorld {
function getString(): Str =
"Hello World"
}
42
class Math {
function answerToLife(): int =
2 * 21
}
Pattern Matching
import {Pair} from std.tuples;
class Opt<T>(
None, Some(T)
) {
function <T> some(v: T): Opt<T> =
Opt.Some(v)
method either(other: Opt<T>): Opt<T> =
match (this, other) {
(Some(v), _) -> Opt.Some(v),
(_, Some(v)) -> Opt.Some(v),
(None, None) -> Opt.None(),
}
}
Type Inference
class TypeInference {
function <A, B, C> pipe(
a: A, f1: (A)->B, f2: (B)->C
): C = f2(f1(a))
function main(): unit = {
// n: int
// s: string
let _ = TypeInference.pipe(
1,
(n) -> Str.fromInt(n),
(s) -> s.toInt()
);
}
}
About the Documentation Site
This is an interactive documentation site where all the code snippets of samlang are editable. These snippets, available after the introduction section, contain inline comments to illustrate the power of the language.
You can click the Demo button at the top of the page or follow this link.
Power and Limits of Type Inference
The only absolutely required type annotated happens at the top-level class function and method level. Most other types can be correctly inferred by the compiler and can be omitted from your program.
The type checker uses local type inference to infer types of most expressions. Therefore, it cannot infer types from the whole program like OCaml does. Instead, it will push down type hints from local, nearby contexts.
Despite the fundamental limitation, the compiler can correctly infer most of the local expression types. If your code does not use generics or unannotated lambda parameters, then all types can be inferred correctly. Most of the type arguments can be inferred, so they do not need to be explicitly supplied. Unannotated lambda parameters with local context but without parametric polymorphism can also be inferred perfectly.
Even when you combine polymorphic function call and unannotated lambda parameters, the type checker still attempts to infer the types from left to right. It will work in most of the code. An illustratin type inference example is available near the top of the page.