← Tutorials / docs

Learn Intlang by Example

If you (like me) learn best by seeing examples and are familiar with functional programming language this should get you up to speed.

let (rec) (and)

let a = 5

binds 5 to a

let rec fib = \n. if 1 < n then (fib (n-1) + fib (n-2)) else (n==1) end

defines the recursive function fib.

let rec collatz = \n cnt. if n == 1 then cnt else if n % 2 == 0 then collatz_even n cnt else collatz_odd n cnt end end
and collatz_even = \n cnt. collatz (n / 2) (cnt + 1)
and collatz_odd = \n cnt. collatz (3*n + 1) (cnt + 1)

defines three functions that are all mutually recursive

main

let main = \() ()

a top-level (global) let binding with the name main must be of type unit->unit and is called after all top-level binding are evaluated.

Expressions

The sub sections that follow introduce different types of expressions. These expressions can be used as right hand sides of top-level let bindings.

lambdas

\x. x

is the identity function

\f g x. f (g x)

is 3 lambdas written as one, it is equivalent to:

\f. \g. \x. f (g x)

Note: In intlang all functions/lambdas are curried by default.

\i : i32. i

is the identity function but annotates that i must be of i32 type

\i : i32 => i32. i

also annotates that an i32 must be returned

\(i : i32) (j : i32) => i32. i+j

for more than argument it looks like this

let (rec) in

let a = 5 in a+3

binds 5 to a and then evaluates a+3 with this binding

let rec fib = 
    \n. if 1 < n then (fib (n-1) + fib (n-2)) else (n==1) end 
in fib 4

binds the recursive fibonacci function to fib and evaluates fib 4 with the new binding

sequence

a; 
b

Evaluates a and then b. A must be of unit type. The parsing on this can be unintuitive at them moment: ; has lowest precedence (even lower than let in) so it is often necessary to put parenthesis around code with ;. Might change this in the future.

unit

()

is the unit literal

\() 5

is a special lambda expecting unit as argument and returns 5 in this example.

i32

4

is a i32 literal

i8 / strings

'f'

is an i8 literal

'\xff'

is an i8 literal in hex notation

if than else end

if a then 4 else 7 end

returns 4 if a (needs to be i32) is non zero and 7 otherwise

unary and binary operation

For both i32 and i8 there are a number of unary and binary operations:

Bopi32:

==  !=  <  >  <=  >=
<u  >u  <=u  >=u
+  -  *  /  %
/u  %u
&  |  ^
<<  >>  >>u

Uopi32:

- ~

Bopi8:

==i8  !=i8  <i8  >i8  <=i8  >=i8

these return i32 (comparisons)

+i8  -i8
&i8  |i8  ^i8

these return i8

Uopi8:

-i8 ~i8

tuples

let t = (4,4) in ...

creates a new tuple bound to t with two i32 values both 4.

let (a,b) = t in ...

Extracts the fields form tuple t.

let (a,_) = t in ...

_ can be used to ignore some part of the tuple

vectors

vec[1,2,3]

creates a vector with i32 elements 1,2 and 3

vecmk[99,5]

creates a vector of length 5 with all elements set to 99

vecmk[77,4,2]

creates a vector of length 4 with all elements set to: vectors of length 2 with all elements set to 77. This is a 2-D vector, vecmk can create N-D vectors by just adding more dimension sizes.

let v = vec[1,2,3] in
vecget[v, 0]

gets the first (zero indexed) element from v ie. 1

let v = vec[vec[1,2,3], vec[11,22,33]] in
vecget[v, 1, 2]

gets the third element of the second element of v ie. 33

let v = vec[1,2,3] in
vecset[v,55, 1]

creates a new vector what is equal in value to v but has the second element set to 55 ie. vec[1,55,3]

let v = vec[vec[1,2,3], vec[11,22,33]] in
vecset[v, 44, 0, 2]

creates a new vector what is equal in value to v but has the third element of the first element set to 44 ie. the same as vec[vec[1,2,44], vec[11,22,33]]

vecget and vecset can index into N-D vectors like this by just adding more indexes

let v = vec[1,2,3,4] in
vecslice[v,1,2]

creates a new vector that is equal in value to a slice of v starting at offset 1 and of length 2 ie. the same as vec[2,3]

let v = vec[1,2] in
vecextend[v,3,2]

creates a new vector that is equal in value to v with 3 appended twice ie. the same as vec[1,2,3,3]

let v = vec[1,2] in
vecextend[v,5,-3]

creates a new vector that is equal in value to v with 5 prepended three times ie. the same as vec[5,5,5,1,2]

strings

"intlang"

is a string literal. strings are just sugar for vector literals with i8 elements. "intlang" is the same as vec['i','n','t','l','a','n','g']

comments

-- this is a comment

-- starts a line comment.

builtins

The following functions are builtin to the language:

  • readi8 has type unit->i8 and reads a char (from stdin)
  • writei8 has type i8->unit and writes a char (from stdout)
  • flush has type unit->unit and flushes stdout
  • i32_to_i8 has type i32->i8 and truncates a i32 to an i8
  • i8_to_i32 has type i8->i32 and zero extends an i8 to i32

include

include io

let main = \() (
    io.write_ln "hello, intlang"
)

Includes the io module (.intlang file) and used the write_ln form it to print "hello, intlang".

Intlang also supports relative included (include location relative to current module) but it is disabled here.

The Lib contains all things that can be included in the Playground.

IO

The io library is probably the most useful when interacting with intlang programs. Here are probably the most useful functions:

  • io.read_ln: takes an [i8] (string) and prints it to the terminal
  • io.write_ln: takes unit (nothing), reads a line from the terminal
  • io.readln_i32: takes an i32 (int) and prints it to the terminal (with trailing line break)
  • io.writeln_i32: takes unit (nothing), reads a line containing an i32 from the terminal
  • io.readln_i32vec: takes an i32 vector and prints it to the terminal (comma separated and with trailing line break)
  • io.writeln_i32vec: takes unit, reads a line containing comma separated i32's from the terminal

More formal vector operations semantics

  • All kinds of indexes, dimensions and offsets need to be of i32 type

  • Vectors are 0-indexed ie. the first element of a vector has index 0

  • All elements of a vector must be of the same type

  • Vectors can have element types: vector, i32 and i8 (might change in the future)

  • <..> denotes not just an expression but rather a comma separated list of expressions

  • vec[<litlist>]: create a vector

    • <litlist> must be a comma separated list of literals
    • Returns a vector of length equal to the number of elements in <litlist>, with the order of <litlist> preserved and the left most element of <litlist> at index 0
  • veclen[v]: get the length of a vector

    • returns the length of the vector v as an i32
  • vecget[v, <idxlist>]: access a vector

    • <idxlist> must be a comma separated list of indexes
    • If <idxlist> is emtpy v is returned
    • Else <idxlist> has a left most element idx then vecget[v_inner, <idxtail>] is returned, where v_inner is the value stored at index idx in v and <idxtail> is <idxlist> without its left most element
  • vecset[v, value, <idxlist>]: create e new vector based on the old one

    • <idxlist> must be a comma separated list of indexes
    • If <idxlist> is emtpy value is returned
    • Else <idxlist> has a left most element idx then v' is returned where v' is equal (in value not physical) to v but has the value at index idx set to vecset[v_inner, value, <idxtail>], where v_inner is the value stored at index idx in v and <idxtail> is <idxlist> without its left most element.
  • vecmk[lit,<dimlist>]: initialize a vector

    • <dimlist> must be a non empty comma separated list of indexes
    • If <dimlist> has a single element dim the result is a vector of length dim with value lit at at every index.
    • Else <dimlist> has more than one element with a left most element dimhead and the rest of the list <dimtail> then the result is a vector of length dimhead with vecmk[lit, <dimtail>] at every index
  • vecslice[v, start, len]: slice a vector

    • returns vector equal (in value not physical) to a slice/section of v starting at index start of length len.
  • vecextend[v, lit, off]: extend / expand a vector

    • If off is positive: returns a vector equal (in value not physical) to v with vecmk[lit, off] appended
    • If off is negative: returns a vector equal (in value not physical) to v with vecmk[lit, -off] prepended