5

I know that pure functions are in the "functional programming" paradigm, you create a function that doesn't have any side effects and that for a input it always return the same output like:

function (a,b) {
    return a + b;
}

This is a pure function because for a input I always return the same output and I didn't create any side effects. Ok I got that.

But how can I make "pure functions", how can I stay in the "functional programming" paradigm when I actually want to create a side effect, such as changing a text content in the DOM, like :

function changeContent () {
   let content = document.querySelector("#content");
   content.textContent = 'Hello World';
}

This function has a side effect, it is not getting a input a return a output, it is creating a side effect, but that is actually the point of the function. Is this still "functional programming"? How to stay in the "functional programming" paradigm in that case?

Plínio Helpa
  • 137
  • 1
  • 9
  • 2
    In 100% pure rigorous functional programming, e.g. Haskell, side-effects are expressed as special types and introduce all new paradigms. That simply doesn't translate very well to Javascript. Javascript is a *multi-paradigm* language which is *not* 100% pure functional programming… – deceze May 28 '18 at 14:41
  • 3
    @deceze You don't have to be pure by design to use algebraic data types or functors et al. It's all about policies in Javascript. –  May 28 '18 at 16:33
  • This q is too broad. Here is a broad answer: Encode your side effect with a type and define, for which behavior this type is equivalent to other types. Additionally, you need some specific combinators, that's it. –  May 28 '18 at 16:35
  • [Ch 8 - Tupperware](https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch08.md#old-mcdonald-had-effects) of *Mostly Adequate Guide to Functional Programming* talks about this – Mulan May 28 '18 at 17:09

2 Answers2

4

How can I stay in the "functional programming" paradigm when I actually want to create a side effect?

You cannot really. A pure function must not have any side effect.

Of course, this means that we cannot actually model a program that does anything as a pure function. There are two ways out of this:

  • Sacrifice purity. Just write a function with a side effect. Document it thoroughly so that everyone using the function know about this. Reason differently about the imperative parts of your program.

    This is the go-to solution in most programming languages, as they don't enforce purity and you can often enough get away with it.

  • Build a (pure) data structure that explicitly describes the effects you want your program to have. Then have an impure "interpreter" that executes them to "run" your program. (I won't go into details here how such a data structure could work, there are different approaches and an explanation would go beyond the scope of the question).

    In Haskell, which enforces purity of all functions, this data structure is the IO type that basically describes an imperative computation and the interpreter for it is built into the runtime.
    In Elm, which also guarantees purity, there is the Elm architecture to model working with web APIs and the DOM in a browser, and a small runtime is required for every program when compiling to JS.

In JavaScript, there is no such interpreter. You can build one yourself (or use a library built for that purpose), but eventually you have to call its run function somewhere in your program which takes you back to #1.

For the DOM specifically: a data structure to describe alterations in the document would be relatively easy to build. You could even introduce purely functional optimisations that e.g. would avoid writing multiple times to the same location, or to locations that subsequently will be removed anyway.

However, the DOM is fundamental part of JavaScript's asynchronous nature. Describing potentially-concurrent interaction with eventful inputs and outputs is hard.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
-1

I'm not sure if it is helpful but you can pass DOM content to the function and get a new one as a result. like this:

function changeContent(content, value) {
    let result = deepcopy(content);       //copy the passed object to preserve it from modifying
    result.textContent = value; //change smth in copied object
    return result;
}

deepcopy is a fuction that returns a copy of an object (if you set directly result = content, than changing some values in result object will also cause changing values in content object). NOTE: deepcopy isn't a built in function you should write it yourself or use a library.

P.S. if this answer isn't helpful you can read an article about functional programming here

  • after returning the modified object you can set it to the DOM content but it's much better to modify content inside functions if this is what you want (it's much faster and easier). – Tornike Bakuradze May 28 '18 at 14:53
  • 2
    While you can do what you have described, it is rather pointless because you still need to modify DOM afterwards, you just delayed the inevitable, and you've made it even worse because now you have the same side effects, but you need to delete DOM element and replace it with new one, which is much harder, expensive and sometimes even dangerous if there are event listeners attached to that element, then just modify the element in-place. – Matus Dubrava May 28 '18 at 21:43