/subskell

Functional language with type inference and let-polymorphism

Primary LanguageOCaml

Subskell

Subskell is a small functional language with the following features:

  • Types
    • Integers
    • Booleans
    • First class functions
  • Comments
  • Currying
  • Laziness (call by name)
  • Static scoping
  • Type inference
  • Optional type hints
  • Let polymorphism

Commands

dune exec subskell run <file> to evaluate Subskell code in a file.

dune exec subskell annotate <file> to view the source code with type hints generated by the type inference algorithm.

dune test to run the provided tests.

Examples

The pieces of code below may also be found in examples/.

Powers of 2

The code below illustrates the use of features such as comments, type hints, recursion and currying.

let n : int = 10 -- n-th power of 2 to compute

-- compute n^m
in let power : int -> int -> int = 
  fun n -> fun m -> if m = 0 then 1 else n*power n (m-1) 

-- compute 2^m
in let powersof2 = power 2

in powersof2 n

Equality Polymorphism

The example below demonstrates let polymorphism.

let id = fun x -> x
in let eq = (=)
in let eqtrue = (=) true
in let eqzero = (=) 0
in if eqtrue (id true) && eqzero (id 0)
   then id 1337 
   else id 420

The above is equal to:

let id : 'a. 'a -> 'a = fun x -> x
in let eq : 'a. 'a -> 'a -> bool = (=)
in let eqtrue : bool -> bool = (=) true
in let eqzero : int -> bool = (=) 0
in if eqtrue (id true) && eqzero (id 0)
   then id 1337 
   else id 420

Type schemes must be marked explicitly.

Type variables

The example below illustrates what happens when type schemes are omitted.

let id : 'a -> 'a = fun x -> x
in let eq: 'a -> 'a -> bool = (=)
in let five = id 5
in eq

Using the annotate feature on the code above yields us the following output:

Annotated source code of examples/typeschemewithout.sml:

let id : 'a -> 'a = fun x -> x
in let eq : 'a -> 'a -> bool = (=)
in let five : int = id (5)
in eq

Inferred type: int -> int -> bool

eq shares the type variable 'a used in the type hint of id. Then, thanks to the definition of five, we infer 'a = int.

The may not be what the programmer intended.

Type schemes

The below illustrates the previous example with type schemes instead of type variables.

let id : 'a. 'a -> 'a = fun x -> x
in let eq: 'a. 'a -> 'a -> bool = (=)
in let five = id 5
in eq

Running annotate on the above:

Annotated source code of examples/typescheme.sml:

let id : 'a. 'a -> 'a = fun x -> x
in let eq : 'a. 'a -> 'a -> bool = (=)
in let five : int = id (5)
in eq

Inferred type: 'h -> 'h -> bool

In this case, id and eq may be instantiated for any type 'a.