Functional thinking. Part 1

In this series of articles you will learn about the basic principles of functional programming and understand what it means to “think functionally” and how this approach differs from object-oriented or imperative programming.




Now that you have seen some of the reasons for using F #, see the article Immersion in F #. A Handbook for C # Developers , take a step back and discuss the basics of functional programming. What does “functionally functionally” mean, and how does this approach differ from object-oriented or imperative programming?


Changing the way of thinking (Intro)


It is important to understand that functional programming is not just a separate programming style. This is a completely different way of thinking in programming, which differs from the “traditional” approach as much as the current OOP (in the Smalltalk style) differs from the traditional imperative language, such as C.


F # allows non-functional coding styles to be used, and this tempts the programmer to preserve his existing habits. In F #, you can program as you are accustomed to, without changing radically the worldview, and not even imagining what you are missing. However, in order to get the most out of F #, and also to learn how to confidently program in a functional style in general, it is very important to learn to think functionally, and not imperatively.


The purpose of this series of articles is to help the reader understand the background of functional programming and change his way of thinking.

This will be a rather abstract series, although I will use many short code examples to demonstrate some of the points. We will cover the following topics:



Mathematical functions


Functional programming is inspired by mathematics. Mathematical functions have a number of very nice features that functional languages ​​are trying to implement.


Let's start with a mathematical function that adds 1 to the number.


Add1(x) = x+1 

What does this expression really mean? Looks pretty simple. It means that there is an operation that takes a number and adds 1 to it.
Let's add some terminology:




This is what the definition would look like on F #.


 let add1 x = x + 1 

If you enter it in F # Interactive (do not forget about double semicolons), then you can see the result (the "signature" of the function):


 val add1 : int -> int 

Consider the output in detail:



Notice that the type was not specified explicitly, but the F # compiler decided that the function works with ints. (Can this be changed? Yes, and soon we will see it).


Key properties of mathematical functions


Mathematical functions have a number of properties that distinguish them very much from functions that are used in procedural programming.



These properties provide a number of noticeable advantages that functional programming languages ​​try to implement as much as possible in their design. Consider each of them in turn.


Mathematical functions always return the same result for a given value.


In imperative programming, we think that functions either “do” something, or “count” something. Mathematical functions do not consider anything; they are pure mappings from input to output. In fact, another definition of a function is a simple set of all mappings. For example, you can very roughly define the function '' add1 '"(in C #) as


 int add1(int input) { switch (input) { case 0: return 1; case 1: return 2; case 2: return 3; case 3: return 4; etc ad infinitum } } 

Obviously, it is impossible to have a case for each possible number, but the principle is the same. With this formulation, no calculations are performed; only a search is performed.


Mathematical functions are free from side effects.


In a mathematical function, the input and output values ​​are logically two different things, both of which are predefined. The function does not change the input or output data and simply maps the predefined input value from the definition domain to the predefined output value in the value domain.


In other words, the calculation of the function can not have any effects on the input data or anything else of the kind . It should be remembered that the calculation of the function does not actually consider and does not manipulate anything, it is just a search of a laud.


This “immobility” of values ​​is very subtle, but at the same time very important thing. When I do math, I don’t expect the numbers to change as they are added. For example, if I have given:


 x = 5 y = x+1 

Then I do not expect x change when I add 1 to it. I expect to get another number ( y ), and x should remain intact. In the world of mathematics, integers already exist in an immutable set, and the function "add1" simply defines the relationship between them.


The power of pure functions


Those types of functions that have repeatable results and have no side effects are called "pure / pure functions", and with them you can do some interesting things:



Accordingly, if the programming language has the ability to create pure functions, you can immediately get a lot of powerful techniques. And undoubtedly, all this can be done in F #:



"Useless" properties of mathematical functions


Mathematical functions also have some properties that seem not very useful when programming.



These properties are reflected in the design of functional programming languages. It is worth considering them separately.


Input and output values ​​are immutable


Immunable values ​​in theory seem like a good idea, but how can you really do any work if you cannot assign a variable in the traditional way.


I can assure you that this is not such a big problem as you can imagine. In the course of this series of articles, it will be clear how this works in practice.


Mathematical functions always have one input and one output.


As can be seen from the diagrams, for a mathematical function there is always only one input and only one output. This is also true for functional programming languages, although it may not be obvious when first used.
This seems like a big inconvenience. How can you do something useful without functions with two (or more) parameters?


It turns out that there is a way to do this, and moreover, it is absolutely transparent to F #. It is called "currying", and deserves a separate post, which will appear in the near future.


In fact, it will later become clear that these two “useless” properties will become incredibly valuable, and will be the key part that makes functional programming so powerful.


Additional resources


For F #, there are many tutorials, including materials for those who come with C # or Java experience. The following links may be helpful as you learn more about F #:



Several other ways to get started with learning F # are also described.


Finally, the F # community is very friendly to beginners. There is a very active Slack chat, supported by the F # Software Foundation, with rooms for beginners that you can freely join . We strongly recommend that you do this!


Do not forget to visit the site of the Russian-speaking community F # ! If you have any questions about learning the language, we will be happy to discuss them in chat rooms:



About authors of translation


Translated by @kleidemos
Translation and editorial changes are made by the efforts of the Russian-speaking community of F # -developers . We also thank @schvepsss and @shwars for preparing this article for publication.

Source: https://habr.com/ru/post/415189/


All Articles