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 of0
and1
, since a prime must be more than1
(the least prime being2
).None[2:Sqrt[n] | n]
first constructs the range from2
toSqrt[n]
using the range operator:
.a | b
operator tests whether or nota
divides evenly intob
. Attache vectorizes many arithmetic operators; i.e., operators "reach" into arrays. For example,[1, 2, 3] + 4
is equivalent to[1 + 4, 2 + 4, 3 + 4] = [5, 6, 7]
. So,2:Sqrt[n] | n
is roughly the same as[2 | n, 3 | n, ..., Sqrt[n] | n]
. This gives an array of Boolean values (true
orfalse
). 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
return
are 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.