# Functional CoffeeScript programming with the f_context library

Those who are faced with functional programming languages ​​are probably familiar with this design:
``````  fact(0) -> 1
fact(N) -> N * fact(N - 1)
``````

This is one of the classic examples of phase transitions - factorial calculation.
Now it can be done on CoffeeScript with the f_context library, just by wrapping the code in f_context -> , for example:
``````  f_context ->
fact(0) -> 1
fact(N) -> N * fact(N - 1)
``````

How it works
See more examples

#### What the library can do

Modules
Pattern Matching
Destructuring
Guards
Variable _ and Matching Same Arguments

Real-Life Examples

##### Modularity:

By default, f_context returns the generated module, i.e. it can be put in some kind of variable:
``````examples = f_context ->
f_range(I) ->
f_range(I, 0, [])
f_range(I, I, Accum) -> Accum
f_range(I, Iterator, Accum) ->
f_range(I, Iterator + 1, [Accum..., Iterator])
examples.f_range(10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
``````

Using the module directive, you can immediately put a module in a global space,
such as window or global :
``````f_context ->
module("examples")
f_range(I) ->
f_range(I, 0, [])
f_range(I, I, Accum) -> Accum
f_range(I, Iterator, Accum) ->
f_range(I, Iterator + 1, [Accum..., Iterator])
examples.f_range(10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
``````

##### Pattern matching

what is it and why is it needed
Example:
``````  matching_example_1("foo") -> "foo matches"
matching_example_1("bar") -> "bar matches"
matching_example_1(1) -> "1 matches"
matching_example_1(true) -> "true matches"
matching_example_1(Str) -> "nothing matches, argument: #{Str}"
``````

Result:
``````  matching_example_1("foo") #returns "foo matches"
matching_example_1("bar") #returns "bar matches"
matching_example_1(1) #returns "1 matches"
matching_example_1(true) #returns "true matches"
matching_example_1("baz") #returns "nothing matches, argument: baz"
``````

##### Destructuring

what is it and why is it needed
Examples:
``````  test_destruct_1([Head, Tail...]) -> {Head, Tail}
``````

``````  test_destruct_2([Head..., Last]) -> {Head, Last}
``````

``````  test_destruct_3([Head, Middle..., Last]) -> {Head, Middle, Last}
``````

Result:
``````  test_destruct_1([1,2,3]) #returns {Head: 1, Tail: [2,3]}
test_destruct_2([1,2,3]) #returns {Head: [1,2], Last: 3}
test_destruct_2_1([1,2,3,4]) #returns {Head: [1,2], Last: 3, Last1: 4}
test_destruct_3([1,2,3,4]) #returns {Head: 1, Middle: [2,3], Last: 4}
test_destruct_3_1([1,2,3,4,5,6]) #returns {Head: 1, Head2: 2, Middle: [3,4], Last: 5, Last2: 6}
``````

##### Guards

what it is and why it is needed.
Guards are specified through the where directive (% condition%) .
In guards, you can specify a more flexible comparison. Example of calculating the Fibonacci series:
``````  #без гвардов
fibonacci_range(Count) ->
fibonacci_range(Count, 0, [])
fibonacci_range(Count, Count, Accum) -> Accum
fibonacci_range(Count, 0, Accum) ->
fibonacci_range(Count, 1, [Accum..., 0])
fibonacci_range(Count, 1, Accum) ->
fibonacci_range(Count, 2, [Accum..., 1])
fibonacci_range(Count, Iterator, [AccumHead..., A, B]) ->
fibonacci_range(Count, Iterator + 1, [AccumHead..., A, B, A + B])
``````

``````  #с гвардами
fibonacci_range(Count) ->
fibonacci_range(Count, 0, [])
fibonacci_range(Count, Count, Accum) -> Accum
fibonacci_range(Count, Iterator, Accum) where(Iterator is 0 or Iterator is 1) ->
fibonacci_range(Count, Iterator + 1, [Accum..., Iterator])
fibonacci_range(Count, Iterator, [AccumHead..., A, B]) ->
fibonacci_range(Count, Iterator + 1, [AccumHead..., A, B, A + B])
``````

##### Variable _ and matching the same arguments

The _ variable is used to "reset" the arguments, if their value is not important, but the number of arguments is important.
Example of the implementation of the all function:
``````f_all([Head, List...], F) ->
f_all(_, _, false) -> false
f_all([], _, _) -> true
``````

If you set the same names for the arguments, they will be automatically compared.
An example implementation of the range function:
``````f_range(I) ->
f_range(I, 0, [])
f_range(I, I, Accum) -> Accum
f_range(I, Iterator, Accum) ->
f_range(I, Iterator + 1, [Accum..., Iterator])
``````

##### Life examples

Sometimes it is much more convenient to implement a particular algorithm using recursion.
For example, reduce and quick sort functions in a functional style:
``````f_context ->
f_reduce(List, F) ->
f_reduce(List, F, 0)
f_reduce([], _, Memo) -> Memo
f_reduce([X, List...], F, Memo) ->
f_reduce(List, F, F(X, Memo))
``````

``````f_context ->
f_qsort([]) -> []
f_qsort([Pivot, Rest...]) ->
[
f_qsort((X for X in Rest when X < Pivot))...,
Pivot,
f_qsort((Y for Y in Rest when Y >= Pivot))...
]
``````

In my opinion, it is simpler and clearer than their imperative counterparts.

#### How it works

Let's get back to the very first example in this article - factorial calculation.
``````  fact(0) -> 1
fact(N) -> N * fact(N - 1)
``````

In CoffeeScript, this is an absolutely valid construct.

An example is more complicated, counting the number of elements in a list in a functional style:
``````  count(List) ->
count(List, 0)
count([], Iterator) -> Iterator
count(List, Iterator + 1)
``````

And this is also valid CoffeeScript code.
Thus, we can write in the usual style for functional languages ​​directly on coffee, without the need to use a precompiler.

For clarity, I will continue to talk on the example of the same factorial. So
this code:
``````  fact(0) -> 1
fact(N) -> N * fact(N - 1)
``````

translates to js as follows:
``````  fact(0)(function() {
return 1;
});
fact(N)(function() {
return N * fact(N - 1);
});
``````

It can even be executed, but with "ReferenceError" errors, that fact and N are not declared.
You can wrap this code in a wrapper function so that it is passed as an argument
``````  function_wrapper ->
fact(0) -> 1
fact(N) -> N * fact(N - 1)
``````

in js we get the following:
``````function_wrapper(function() {
fact(0)(function() {
return 1;
});
fact(N)(function() {
return N * fact(N - 1);
});
});
``````

Now function_wrapper can analyze the function passed to it in the
argument and pass all the missing variables to it. Something like this:
``````var function_wrapper = function(fn){
var fn_body = fn.toString().replace(/function.*\{([\s\S]+)\}\$/ig, "\$1");
var new_function = Function.apply(null, fn_body, /*именованные аргументы*/ 'fact', 'N');
var fact_stub = function(){
return function(){};
};
// маркируем N как переменную
var N_stub = function(){};
N_stub.type = "variable";
N_stub.name = "N";
new_function(fact_stub, N_stub)
}
``````

Now the code is executed without errors, but so far does nothing.
Next up is fact_stub , which can also parse its arguments and
generate its local branch of the current function. For a factorial, it will look something like this: After the parsing tree is built, you can easily generate a module and create it through the same Function.apply.
The module body should look like this:
``````var f_fact_local_0 = function(){
return 1;
};
var f_fact_local_1 = function(N){
return N * f_fact(N - 1);
};
var f_fact = function(){
if(arguments === 0){
return f_fact_local_0();
}
return f_fact_local_1(arguments);
};
return {
f_fact: f_fact
};
``````

In fact, everything is a little more complicated, but here I tried to state the basic principles of work.
If the article is not clear - write, I will try to fix it.

The library itself is here: github.com/nogizhopaboroda/f_context

Any comments are welcome. Like feature requests.

Only registered users can participate in the survey. Please come in.

## Is the article clear?

• 54.9% Understand 28
• 25.4% Don't understand 13
• 33.3% What is it all about? 17