Thinking Functionally
If you started programming in a language like C or Java (before 1.8), then you're probably used to imperative (or declarative) programming. This typically involves constructs such as if statements and variants of while loops. Typically, this type of programming usually works by building up data from inputs.
Functional programming differs from imperative programming since it's much better at generating data to be mapped and filtered. Attache is more of a functional language, which depends less on modifying the program's state directly with variables and more on using functions to transform data.
To explore the difference, let's write a function to check if a number n is prime. In C, you might write something like this:
uint isqrt(uint); // returns floor(sqrt(n))
bool is_prime(uint n) {
if(n < 2) return false;
uint upper = isqrt(n);
for(uint i = 2; i < upper; i++) {
if(n % i == 0) return false;
}
return true;
}
You could write a function that uses the same type of constructs, but it'd look different. Attache lacks the for loop as a syntactic construct, as well as if or while loops. Such logic is achieved using functions. Emulating a for loop would be quite awkward without devising new functions, and this is an intentional design choice. This is how I would implement a prime-checking function in Attache:
is_prime[n] :=
n > 1 and None[2:Sqrt[n] | n]
This defines a function is_prime which takes a single argument n and checks if two conditions hold:
n > 1. This covers the corner cases of0and1, since a prime must be more than1(the least prime being2).None[2:Sqrt[n] | n]first constructs the range from2toSqrt[n]using the range operator:.a | boperator tests whether or notadivides evenly intob. Attache vectorizes many arithmetic operators; i.e., operators "reach" into arrays. For example,[1, 2, 3] + 4is equivalent to[1 + 4, 2 + 4, 3 + 4] = [5, 6, 7]. So,2:Sqrt[n] | nis roughly the same as[2 | n, 3 | n, ..., Sqrt[n] | n]. This gives an array of Boolean values (trueorfalse). Then,None[...]checks that no value in the input array is truthy.
In essence, this function asserts that n is greater than 1 and that no number in the range from 2 to the square root of n divides n. This function showcases Attache's minimal syntax:
- Functions can be defined the simple structure
name[a, b, c, ...] := body. Compare this to other languages (Java, Python, Ruby, JavaScript) which often require some additional keyword to create a function. - No keywords like
returnare necessary to yield the value; it is implied. - Vectorizing allows the programmer to omit constructs like maps, overloading otherwise unused behaviour. Tripling each member in an array in most languages is something like
[1, 2, 3].map(e => e * 3)ormap(lambda x: x * 3, [1, 2, 3]); in Attache, this expression is simply[1, 2, 3] * 3. - Operators exist for common operations:
:for a range,|for divisibility, e.g.