Floof is a minimal functional language comprised entirely of one object type:
T ::= T -> T. The exception to this are the reserved functions that take in user input, which has no arguments, and the reserved functions that prints, which has side effects.
A function in Floof consists of an
argument_name and a
definition. The syntax is as follows:
The function can then be called as such:
[f:f] ; Identity function [f:[x:f(f(x))]](g)(y) ; Equivalent to g(g(y))
The only literals in Floof are nonnegative integers and implemented as special functions of type
T. The integer
n is implemented as a function that takes in a function
f and an object
x and returns
[f:[x:x]] ; Represents the literal `0` [f:[x:f(x)]] ; Represents the literal `1` [f:[x:f(f(x))]] ; Represents the literal `2`
Input and Output
Floof takes in either integers or char, and can output (print) in either integer or char. Several reserved names are used for these:
_IN_INT_() ; Waits for user to input a non-negative ; integer and returns it in the representation ; mentioned above _IN_CHAR_() ; Waits for user to input a character and ; returns an integer representing the Unicode ; code point of that character, in the ; representation mentioned above _OUT_INT_(arg) ; Prints the integer represented by `arg` of ; type `T`. Returns `arg`. _OUT_CHAR_(arg) ; Prints a char in the Unicode code indexed by the ; integer represented by `arg` of type `T` ; Returns `arg`.
_OUT_INT_( [f:[x:x]] ) ; Prints `1`
_OUT_CHAR_( _IN_CHAR_() ) ; Waits for user to input a character and echos it out
Comments start with a
;. Everything in a line after a
; is ignored and treated as a comment.
A Floof program consists of several macro blocks and a main block. Each block starts with either a
# or a
! and ends with a
~. Each block can contain only one expression. Everything after the main block is ignored.
Macro blocks are meant to modularise the program. The Floof compiler merges all macro blocks with the main block before running. Once defined, they can be used further down in the program. Macro blocks cannot reference themselves. They have the following format:
#<macro_name> <macro_definition> ~
macro_name must follow these conditions:
- Start with a letter or the underscore character.
- Cannot start with a number.
- Can only contain alpha-numeric characters and underscores (A-z, 0-9, and _)
- Case-sensitive (age, Age and AGE are three different variables)
macro_definition must consist of a single expression.
Macros are also defined top down. A macro cannot reference a macro below it in a file.
#N0 ; Represents the integer 0 [f:[x:x]] ~ #INC ; INC(a) computes a+1 [n: [f: [x: f(n(f)(x)) ] ] ] ~ #N1 ; Represents the integer 1 INC(N0) ; Used the above macros ~ #N2 ; Represents the integer 2 INC(N1) ~
Each Floof program can only contain one main block. The main block is what the interpreter will run. Any macros that the main block uses must be defined above it. They have the following format:
! <main_definition> ~
main_definition must consist of a single expression.
! ; Prints `1` _OUT_INT_( [f:[x:x]] ) ~
#N1 ; Represents the integer 1 [f:[x:f(x)]] ~ #INC ; INC(a) computes a+1 [n: [f: [x: f(n(f)(x)) ] ] ] ~ ! ; Prints `2` _OUT_INT_( INC(N1) ) ~
Running a Floof program
A Floof to Python compiler can be found here