5D Tutorial

Syntax Elements

Names can contain every printable character except space and # and @, although operator names consist of different characters than other names.

Usually, operator names consist of funny characters or math operator characters, not alphanumeric letters.

Some operators are preregistered (most important first): . _ ^ ** * / : ' ++ + - % = /= < <= > >= && || , $ else elif | => ; \ let import

Monoms after a name are function arguments: sin k⋅x=sin(k⋅x) and not (sin k)*x.

On the other hand, sin k⋅x+φ=(sin k⋅x)+φ

Likewise, 5⋅f x=(5⋅f) x and not 5⋅(f x)

Programming by example

Hello world

#!/usr/bin/λ -i
let IO := requireModule "IO" in 
import [write! stdout] from IO in 
write! stdout "Hello world"

Note that you need to specify (using -i) that you want IO to happen (rather than just be described).

What this does is:

write! \file \text will write text, once a World is given (i.e. by calling the interpreter with -i or chaining actions with ;).

Mathematics

The usual calculator mathematics work (note: no -i):

#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+)] from Arithmetic in 
(5 + 2) => 7
#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+) (⋅)] from Arithmetic in 
(5 + 2⋅3) => 11

Operator precedence is as you would expect:

#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+) (⋅)] from Arithmetic in 
(5 + 2⋅3) => 11
#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+) (⋅)] from Arithmetic in 
let f := \x x⋅x in 
(5 + 2⋅(f 3)) => 23

Here, the function f is defined to be a function of x, giving the square of x.

Then the function f is evaluated with the argument 3.

However, there is one strange quirk: 2⋅f x means (2⋅f) x:

#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+) (⋅)] from Arithmetic in 
let f := \x x⋅x in 
(5 + 2⋅f 3) => ???

The following works, too (although it has more parens for no reason):

#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+) (⋅)] from Arithmetic in 
let f := \x x⋅x in 
(5 + 2⋅(f(3))) => 23

Or if it's the first operand of multiplication:

#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+) (⋅)] from Arithmetic in 
let f := \x x⋅x in 
(5 + (f 3)⋅2) => 23

Note that * works for multiplication as well (and is the same thing):

#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
import [(+) (*)] from Arithmetic in 
(5 + (f 3)*2) => 23

Conditionals

#!/usr/bin/λ
let Arithmetic := requireModule "Arithmetic" in 
let Logic := requireModule "Logic" in 
let Composition := requireModule "Composition" in 
import [(≥)] from Arithmetic in 
import [(if) (else)] from Logic in 
import [($)] from Composition in 
let abs := \x if (x ≥ 0) x else (-x) in 
abs (-2) => 2

Logical Operators and Logical Functions and Logical Values

#!/usr/bin/λ
let List := requireModule "List" in 
let Testers := requireModule "Testers" in 
let (=>) := Testers.(=>) in 
List.allTrue? [
#t => #t
#f => #t
#f && #f    => #f
#f && #t    => #f
#t && #f    => #f
#t && #t    => #t
#f || #f    => #f
#f || #t    => #t
#t || #t    => #t
#t || #t    => #t
not #f      => #t
not #t      => #f
]

Lists

The simplest form of list is the linked list.

Nodes of a linked list are created by : like this:

#!/usr/bin/λ
let List := requireModule "List" in 
import [(:) nil] from List in 
42:24:12:nil

This is a list with 3 elements, linked together through the tail. The last element has nil tail.

There's also a shorthand macro for creating lists used like this:

let List := requireModule "List" in 
import [(:) nil] from List in 
[42 24 12]

You can access elements like this:

#!/usr/bin/λ
let List := requireModule "List" in 
import [(:) nil head tail cons? list? allTrue?] from List in 
allTrue? [
head (1:2:3:nil)            => 1
tail (1:2:3:nil)            => (2:3:nil)
head (tail (1:2:3:nil))     => 2
cons? (1:nil)               => #t
cons? nil                   => #f
cons? 42                    => #f
list? (1:nil)               => #t
list? nil                   => #t
]

Literal Names

Sometimes you want to not reduce a function or operator to their definition but rather leave the name. To do so, prefix their name by '

let x := 2 in 
'x => x

However:

let x := 2 in 
x => 2

Keyword Arguments

#!/usr/bin/λ -i
REPL.import! "IO"
fopen @mode:"w" "foo.INI.temp"        -- Keyword Arguments need to be before normal arguments.

Conditionals

Conditionals are used for flow control.

If you want to see a short result on screen, use something like the following:

#!/usr/bin/λ
let Logic := requireModule "Logic" in 
let Testers := requireModule "Testers" in 
let (=>) := Testers.(=>) in 
if (#t && #t) 'yes else 'no => 'yes

I/O

#!/usr/bin/λ -i
let IO := requireModule "IO" in 
import [write! flush! readline! return! stdout] from IO in 
write! stdout "What's your name? " ;\_
flush! stdout ;\_
readline! stdin ;\name
write! stdout "Hello " ;\_
write! stdout name ;\_
flush! stdout ;\_
return! name

What this does is:

write! \file \text will write text, once a World is given (i.e. by interpreter option -i or ;).

; will sequence two operations so the left-hand-side operation will be done first and the result of that operation given to the right-hand-side - which results in an operation, which will be done afterwards.

_ is the traditional variable name for "don't care about the argument".

Indentation

If you want to spread your program over multiple lines, you can. However, then, indentation rules come into effect.

let Arithmetic := requireModule "Arithmetic" in 
let Logic := requireModule "Logic" in 
let Composition := requireModule "Composition" in 
import [(if) (else) (elif) (=)] from Logic in 
import [($)] from Composition in 
import [(=)] from Arithmetic in 
if (x = 0)
  1
elif (x = 1)
  2
elif (x = 2)
  3
else 
  4

These work as follows:

If the indentation (number of whitespace characters at the beginning of the line) increased compared to the previous line, then a "(" is inserted.

If the indentation decreased compared to the previous lines, then one or more ")" are inserted until previous blocks up to and excluding the current block are closed.

Abbreviations

Single Abbreviation

If you want to abbreviate some formula you use often, you can use the let macro.

let a := b in c expands to (\a c) b, the macro argument order being more common for programmers.

Example:

let pi := 3.141592 in 
2⋅pi

Result is:

6.283184

Because:

((\pi 2⋅pi) 3.141592) => 6.283184

Mass Abbreviation

If you want to abbreviate a lot of lets, you can use the import macro.

import [a b c d] from F in B expands to:

let a := F.a in 
let b := F.b in 
let c := F.c in 
let d := F.d in 
B

For example:

let Arithmetic := requireModule "Arithmetic" in 
import [(+) (-) (*) (/)] from Arithmetic in 
5 + 2*3

REPL

The interactive interpreter has a few special features, available through the module "REPL" which is automatically imported for you and made available under the name REPL:

REPL Environment Extension

If you keep needing the same definitions all the time, you can add them to the environment of the REPL and have them available automatically in the future:

REPL.import! "IO"

Note that this will import everything from the module "IO", possibly overriding your own definitions of things of the same name.

Reflection

Sometimes you want to know how a function was originally defined (as opposed to how it was actually implemented).

Therefore, the λ REPL has a command to retrieve the original definition of things in its environment:

Note that you need to put parenthesis around operators (in order to prevent them from asserting their own precedence).

REPL.import! "IO"
REPL.define! 'f \x x*x
REPL.describe! 'f => \x x*x
REPL.describe! '(;) => \m \ber \world (\r ber (ioValue r) (ioWorld r)) (m world)

If there are multiple overrides for the definition, try using @backOffset: to reach back. The value is an integer starting at 0 (which is the default) stating how many definitions (of that symbol) back you want to reach.

REPL.describe! @backOffset:1 'g => \x x*x

Recursion

Usually, the function name is not available within the function:

REPL.define! 'f (\x (f 1))      -- makes no sense

If you want it to do recursion, do it like this:

REPL.import! "Composition"
REPL.define! 'f (rec \f \x (f 1))      -- endless recursion, but it works

Or like this, which is exactly the same:

REPL.import! "Composition"
REPL.define! 'f (rec \self \x (self 1))      -- endless recursion, but it works

Note that the reason that define! 'f doesn't make f available within the body of f is that you can refer to previous definitions of f within the new definition of f.

An example will make that clearer:

REPL.import! "Logic"
REPL.import! "Arithmetic"
REPL.define! 'f \x (x**x)
REPL.define! 'f \x if (x = 0) 1 else (f x)    -- refers to the previous definition.

Further Reading

See the 5D Library Documentation for functions available to you.