# The docs are a bit of a mess right now, go check here

## The article is incomplete for now, don’t worry, I’m working on it

This isn’t the most interesting article on CF, but it has all the info you need to make your own CF compiler / interpreter !
If your language fits all these requirements, it is considered as an official copy of CF.
Feel free to Ctrl+F properties you need info on.
Current version: 0.3.0

# Philosophy

CF is a multiparadigm language, that supports functionnal features, and tries to make the devs write good, error-proof code.
It can be compiled to any target of your choice, and made compatible with any other language, as long as all the criteria below are respected.

# Types

All data types are immutable by default, please check Mut for more info

## Primary Types

• i16 is a 16-bits whole number

• Int is a 32-bits whole number

• Long is a 64-bits whole number

• Float16/32/64 is a 16/32/64-bits decimal number

• Num is a Float x, where x depends on the implementation (usually 32)

• Char is a standard utf-8 character

• String is a list of Char of variable length

## Composite Types

• (X, Y, ..) or Tuple, is a fixed-length, fixed-type list of values

• [X] is a list of type X, variable length

• X, .. ->> Y is a function, taking arguments of types on the left, outputting types on the right

• (..) means priority. ex: (X ->> Y) ->> Z

• X | Y means a type X or Y

• x | y means a type which can only have values x or y

you can have X | y where X is a type and y is a value

• ### Maybe:

Maybe X is here to try and make you error-handling less painful, and avoid your program crashing. A value of type Maybe X can be either Nothing, which would indicate a problem in code (ie div by 0) without crashing it, or Just x, where x is any value of type X.

• ### Mut:

By default, every piece of data is immutable. If you want to change it at any point, you have to assign it to Mut.
My has 2 variants, Mut X & Const X. By default, any value of type X is also considered Const X.
You can convert any data from one to the other.

Even under Mut, a tuple can’t have values pushed to it, though its properties can be mutated. The only exception is when the tuple ends with ...X.

• ### Empty

is for when you don’t really need any value here. One of the only monads that doesn’t have multiple keywords at all. Empty is the type of an empty tuple, and an empty String / Char / List.

data Empty = Const () | Const [] | Const "" | Const ''

• ### IO

is the dirty Monad. To make any program that influences the outer world, you need to use it. As soon as your function does more than going through lambdas & creating local variables, it is a side-effect, and should be indicated somewhere in the output type. As an input, it means you are reading data from somewhere.

IO, .. ->> .. or .. ->> IO, .. should lead to an error, as it is terrible code, and we don’t allow that.

• ### Show

Show is implemented for all primary types, (quite obvious, I won’t detail it here). It is a typeclass including a .show property, which returns the value as a string.
The String function can be defined as:

• ### Map

Map is one of the proudest features of CF, it operation from an iterable to every single element. You can get a map of any axis a by using the 'a operation.
You can also unmap a value by casting it.

• ### Iterable X

Iterable of type X is a typeclass for anything that accepts indexing, and being turned into a Map, or a List

• ### @

Is the antimonad. @ x gets rid of the hightest-level monad of the value.
@X x gets rid of the monad X on the value.

## Type Mods

• ...Type is any number of Type

• Type * x the same as “Type, Type, ..“, x times

## Casts

If a cast if possible, it can be called using the type name as a function. Float 3 will result in 3.0

## Type Specifics

• i16, Int, Long are represented by a number. If casted from a Float, the number is rounded.

• Float16/32/64, Num are represented by a number, containing a dot. leading and trailing dots are allowed, as in 0. or .9. Can be casted from all number types.

• Num accepts any number type, and automatically does the casting.

• Char is represented by a single char surrounded with ''. Can be casted to String

• String is represented by text surrounded with ""

Numbers in Strings can be casted to Float / Int types, in base 10. The conversion will fail in case of a misformed string.

## Custom Types

• ### Data

1. You can define a new data type using the data keyword.

data NewType = X, where X is any type, ie (String, Int, Num * 2, ...Int)

you can only have 1 ..., in the last element of the type

Those new types are just sugar, and can be inferred from the corresponding primaries.

Creating a new data type creates a new constructor, which takes in as an argument the corresponding composite primaries. i.e NewType ("", 0, 0., 0., 2, 3)

Also, these properties can be accessed in multiple ways:

• my_new_var[0] would then access the string, since under the hood it’s just a tuple, in that case
• You can define keywords while assigning the properties, ie data Point = (Num x, Num y), you can then access my_point.x
1. You can then define custom properties of that type Under the hood, it declares functions, taking in the vector object, computing the value. Types are inferred. You can consider those as macros, as they cannot rely on storing data in the individual object.

## TypeClasses

I’ll use Haskell’s example, which can be found here, for now.

### Checking for TypeClasses

In a generic expression, you can make sure your class is compatible with your typeclasses. Here, we can use the Typeclass / Monad Show, which simply has 1 method, which turns a value to a string.

# Data Flow

All values not part of Mut are immutable by default.

## Namespace

Namespaces are nothing more than a way of organising you code, and scoping more easily.

## Scoping

Scopes are created manually too. At top-level, or in top-level do, you have access to anything global. In functions though, you only have access to what you manually scope using with.

You can use with long_name as short_name to make references less painful to type

Scoping an object, custom datatype, or namespace will scope all its properties

## Generics

When declaring a function, or a class, you can use generics to make the instance apply to any type.

You can also force the input type to be part of a monad / typeclass.

## Destructuring

A list / tuple can always be destructured.
All last elements can be grouped using ....
... works like in JS for destructuring lists, it cannot be used outside of a tuple / list.

# Functions

Functions are values of type X, .. ->> Y. They can be defined at top-level, first by type, then by a sequence of lambdas, which will be pattern-checked, the first corresponding one will be executed.

You can define a name as an operator by wrapping it into ().

## Techical info

Under the hood, if possible, references should be passed in functions, as the inputs aren’t mutable, to save on space, since copying is useless.

## Lambdas

A lambda is defined with a list of arguments (which can be destructured), a “lambda operator”, and a single return value

### Lambda Operators

A lambda operator is any operator that takes in 2 values, followed by > ie =>, +>, *>, >\>, etc.
The lambda will then apply that operator (not =) to the input / expression on the right, and return the result.

I recommend => in most cases, as others are just shorthands

## Pattern-Checks

There are two types of pattern checks:

1. value checks:
2. boolean checks

## Pipelines

A pipeline can be used along with ~>, they’re is a list of sequential lambdas, in curly brackets.

## Do blocks

do blocks can either be used at top-level code, or in lambdas using ~>
They allow the CF imperative syntax to be used in them.
They can return a value, and be used in normal functions.

Top level do blocks have total access over the global scope, and can IO

## Scope

Functions are manually scoped. They cannot access anything not expressed with with

If some of your definitions don’t fit the type of the function, you can declare it multiple times with different types.

## Partial Application

Calling a function without all the arguments will results in another callable function.

A function cannot be defined with a variable number of arguments

Using <x?>, you can choose which arguments you leave blank, and which ones you fill in, where x is the new position of the argument.

# Operators

• ## + - * / ** // %

All the mathematical operators work as expected. (same as python)

Also, here are the definitions for strings.

• ## And &&

And is the standard “and” logic operation

• ## Or ||

Or is the standard “or” logic operation

• ## :=

This is the type check operator

• ## Any |\

Returns True if any of the elements evaluate to True.

The any keyword / function acts the same, but the 2 inputs are reversed.

• ## All &\

Returns True if all the elements evaluate to True

The all keyword / function acts the same, but the 2 inputs are reversed.

• ## Foldl >\

Returns a single value, by mapping through an iterable from the left.

The foldl keyword / function acts the same, but the 2 first inputs are reversed.

• ## Foldr <\

Returns a single value, by mapping through an iterable from the right.

The foldl keyword / function acts the same, but the 2 first inputs are reversed.

• ## Filter \\

Filter gets rid of every element which doesn’t satisfy a condition

The filter keyword / function acts the same, but the 2 inputs are reversed.

• ## Map @\

Map applies a function over a whole array

The map keyword / function acts the same, but the 2 inputs are reversed.

# Classes

You can define a class (which are a bit different from new types) using the class keyword.
Every class need a new method, which returns Make, the new type.
You can instantiate new instances using \$

You can then extend other classes, and inherit their properties.

You can, just like for data types, assign properties outside of the class definition

You also can make properties static, though using a normal namespace is recommended

# Syntax

## Functions

A function’s syntax is as follows

Functions are called by writing their names and then the arguments’ separated by spaces.

To specify left-association, you can use <-, which means f <- X Y Z = f (X Y Z)

## Others

Classes, typeclasses & data are specified above.

do blocks are the only other block allowed iat top-level.

## “Imperative Mode”

Inside do blocks, you get access to new features.

• Local variable assignment with =
• if/elif/else statements, identical to python’s
• for loops, identical to python’s
• while loops, identical to python’s

# Error Handling

We really value great error handling. You’ll need to have access to 1 log file, for the Complete Error CE, and the terminal to display the Summarized Error SE.

## In a do block

The line where this happened should be indicated, as well as the error type. If possible, log all important parts of the scope in the CE, and indicate the call stack (last ~5 elements) in the SE.

## In a Pipeline

Print the line, again, with the error type. The whole call stack should be in the CE, along with the values of the inputs of the function at each point in time during the pipeline’s execution.

## In any other Function

Print the line, error type, callstack in CE, and this time, you can show the inputs to the function in the SE as well, since there’s only one.

## Warnings

• Using with on a Mut variable
• Muting without Copying

# Modules

Modules can be created in .cf files, and parts (functions, classes, typeclasses, datatypes, and namespaces) of it can be importing following this syntax

Modules should have polymorphism if allowed to be imported from another language ie being able to call a function, access a property, etc.

# Standard Library

This is a list of all functions that should be part of the Standard Library, available with or without imports.
These can and should preferably be shared between implementations

## IO (non-optional) (no imports required)

• ### Log

is used to print content to the console, on a new line, and also ends the line

• prints data to the console, without starting nor ending with a newline

• ### Prompt

is used to get a string input from the console (it prints a prompt beforehand)

• ### Raw Input

is used to get a string input from the console

## String (non-optional) (no imports required)

• ### Split

is used to split a text at every occurence of a specified substring.

• ### Join

is used to create a string from an iterable, with a separator

• ### Lower / Higher

are used to change the case of a string.

## Iterable (non-optional) (no imports required)

• ### Fill

fill returns an iterable with a single value repeated, but the same length/structure as the input.

• ### Zip

zip takes in two iterables, and returns a zipped version of the length of the shortest input. zip [1, 2] [3, 4] = [(1, 3), (2, 4)]

• ### Enumerate

enumerate takes in 1 iterable, and associates every element with its index

## Math (non-optional) (imported)

name: "math.cf"

## Re (optional) (imported)

name: "re.cf"

# Memory Management

Every return value / variable is stored separately. Arguments to functions are always references. As soon as a value goes out of scope forever (not cited in any with nor used as an argument anymore), it is deleted.
Copy x returns a copy of a variable.

# Misc

## Ranges

Ranges work just like in Haskell, they are lazy-evaluated and expressed like so

## Misc

• The file extension is “.cf”
• Comments are denoted with #, even though -- is used in this article (syntax highlighting uses haskell’s for now).

# Conventions, and Idiomatic Code

• ## Typing

Variables and functions are written in lowercase.