I've been reading about functional programming and its concepts. It's clear to me that when working in big projects you always need to mix (at some adequate level) multiple paradigms such as OO and functional. In theory, concepts such as function purity are too strict such as
The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices. (https://en.wikipedia.org/wiki/Pure_function)
That said, is this (or can be considered) code a pure function?
const externalVar = 10;
function timesTen(value) {
return externalVar * value;
}
I'm asking this because, in this case, the timesTen
function will always return the same value for an input, and anyone can change the value of externalVar
as this is a constant. However, this code breaks the rule of accessing external function's scope.
Yes. It is guaranteed to be pure.
The reason is that it only depends on bound and immutable free variables.
However, this code breaks the rule of accessing external function's scope.
There is nothing in your quote that says you cannot access free variables. It says external input as reading from a file, network, etc not a free variable from a previous scope.
Even Haskell use global function names like foldr
and it is a free variable in every function it is used and of course the result is pure.
Remember that functions by name is just variables. parseInt
is a variable that points to a function so it would have been hard to make anything at all if every function you should use in another function be passed as parameter.
If you redefine parseInt
to something that is not pure or during the duration of your program so that it works differently then no function calling it would be pure.
Function composition and partial evaluation work because they supply free variables. Its an essential method of abstraction in functional programming. eg.
function compose(f2, f1) {
return (...args) => f2(f1(...args));
}
function makeAdder(initialValue) {
return v => v + initialValue;
}
const add11 = compose(makeAdder(10), makeAdder(1));
add11(5); // ==> 16
This is pure. The closure variable / free variable f1
, f2
, initialValue
never changes for the created functions. add11
is a pure function.
Now look at compose
again. It looks pure but it can be tainted. If not both functions passed to it were pure the result isn't either.
They can easily be combined by not mutating the objects you create.
class FunctionalNumber {
constructor(value) {
this.value = value;
}
add(fn) {
return new FunctionalNumber(this.value + fn.value);
}
sub(fn) {
return new FunctionalNumber(this.value - fn.value);
}
}
This class is purely functional.
In fact you can think of a method call like obj.someMethod(arg1, arg2)
as a function call with obj
as first argument someFunction(obj, arg1, arg2)
. It's only syntactic differences and if someFunction
mutated obj
you would have said it was not pure. This is how it is with someMethod
and obj
too.
You can make classes that work on large data structures that are functional, which means you never have to copy it before changing when doing a backtracking puzzle solver. A simple example is the pair in Haskell and Lisp. Here is one way to make it in JavaScript:
class Cons {
constructor(car, cdr) {
this.car = car;
this.cdr = cdr;
}
}
const lst = new Cons(1, new Cons(2, new Cons(3, null)));
const lst0 = new Cons(0, lst);
lst0
is lst
but with a new element in front. lst0
reuses everything in lst
. Everything from lists to binary trees can be made with this and you can make many sequential data structures with immutable binary trees. It's been around since the 50s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With