Coding style#
Program#
- Every function has to be delimited by one empty line.
- Every (non-scoped) function must have a comment directly above it.
- Tests must appear in a single block (no empty lines) one line under the definition.
See the standard library for inspiration.
Function naming#
De Bruijn indices can be seen as a disadvantage to readability. It's therefore much more important to name the functions appropriately.
For functions that return a boolean, we suggest using the suffix ?
. If
your function has different cases it's recommended to use the case-
prefix in scoped sub-terms.
# from std/Ternary
zero? [0 case-end case-neg case-pos i] ⧗ Number → Boolean
case-end true
case-neg [false]
case-pos [false]
Appropriate type signatures are also encouraged.
If/else#
Since booleans are just lambda terms either returning its first or second argument, the use of if/else procedures is generally redundant. See bit/boolean data structure.
:test (true 'a' 'b') ('a')
:test (false 'a' 'b') ('b')
Head/tail#
The internal structure of the list encoding means that when a list is applied to a function, the function is called with the head and tail of the list.
:test ("abc" [[1]]) ('a')
:test ("abc" [[0]]) ("bc")
Therefore the recommended style for coding with lists is to use
head
/tail
only when truly needed.
Recursion#
Recursion should almost always be achieved with the
y
or z
combinators.
A common coding style in bruijn's standard library is to use the scoped
rec
function to indicate recursion. You would then use n+1
abstraction around rec
to indicate n
arguments and the additionally
induced recursive call.
Example of the length
function for lists:
# 3 abstractions => two arguments
# 2 is recursive call
# 1 is accumulator (+0)
# 0 is argument (list)
length z [[[rec]]] (+0) ⧗ (List a) → Number
rec 0 [[[case-inc]]] case-end
case-inc 5 ++4 1
case-end 1