What is a functional language?
It isn’t easy to define a functional language clearly, but in this article, we will think about it as follows.
In contrast to procedural languages, which are programmed mainly by combining statements and instructions, functional languages ​​are written mainly by combining expressions and functions.
Now, to compare the differences between procedural and functional languages, let’s look at a program that calculates the least common multiple of n1
integers.n2
Procedural language is written in “sentences”
First, let’s look at Java, which is a procedural language.
We will create a program by combining statements such as assignment statements and while
statements. Also, because the value of a variable changes due to assignment, the same statement may produce different outputs, such as the output before and after the statement above. (More details later) System.out.println(n)
while
15
5
In contrast, in functional languages:
Functional language is written using “expressions”
The program to find the least common multiple in the functional language Haskell is as follows.
Functional languages while
​​do not have statements, but are written using combinations of expressions and functions. Using the example above, the second part main
of the function is the function, and the second part is the expression. Even with such a combination of functions and expressions, it is guaranteed that the same program as in a procedural language can be written, that is, it will be Turing complete, and the ability to write programs will not change. euclid
print
euclid n1 n2
print $ euclid n1 n2
Referential transparency and side effects
Writing only expressions like in Haskell means that variables are not rewritten like in assignment statements. In other words, all variable values ​​and functions are defined only at the time of declaration and are immutable declarations that cannot be rewritten later. This specification satisfies referential transparency as shown below and has no side effects. Here, referential transparency means that if you pass the same argument to the same function, it will always return the same result, and side effect means that other external variables or states are rewritten within the function.
In short, to summarize
- Referential transparency: not affected by external influences
- No side effects: no external effects
about it. A function that satisfies both of these is called a pure function, and a functional language in which (almost) all functions are pure functions, such as Haskell, is called a pure functional language.
In principle, programs that include external input and output are not referentially transparent and include side effects, so at first glance it seems that pure functional languages ​​cannot handle these processes. However, if it is possible to separate the part where input/output occurs from the pure part, it can be called a pure functional language. In fact, this is achieved by using things like monads. (This is what I mean when I say that almost all functions are pure.)
Focus on referential transparency
Scala, which is sometimes called a functional language, is object-oriented and is not a purely functional language, but it is a language that is highly conscious of referential transparency, whether it is mutable or immutable, that is, it cannot be changed later. That’s one. There are two types of variable definitions: mutable var
and immutable, and they are separated into two libraries. val
mutable
immutable
Programs written in languages ​​that satisfy referential transparency have the following characteristics:
Characteristics of languages ​​that satisfy referential transparency
The following are the characteristics of a program that satisfies referential transparency, such as Haskell.
Easy to test and fix bugs
In the case of a program that satisfies referential transparency, the values ​​of variables and the execution of functions do not change depending on the context, so only unit tests can be completed, and even if an error occurs, only the definition needs to be checked, making it easier to fix bugs. It will be relatively easy. In the case of a program that does not satisfy referential transparency, its output may depend on the context, so if a bug occurs, it may be necessary to check not only the definition but also the surrounding context, which saves time and effort. It takes.
Easy to perform parallel processing
In a program that satisfies referential transparency, each function always returns the same value for the same input, regardless of the order of execution. Therefore, if the input values ​​are the same, it is guaranteed that the result will not change even if parallel processing is performed. For languages ​​that are not referentially transparent, the return value may change depending on the program execution order, and some programs are unsuitable for parallel processing.
It is necessary to consider the balance with external input/output.
If there is input/output from an external database, etc., functions that read will no longer satisfy referential transparency, and functions that rewrite will, in principle, no longer satisfy purity because they have side effects that affect the outside world. Therefore, the question becomes how to handle such functions. In the case of the pure functional language Haskell, a mechanism called a monad is used to separate functions that are not reference transparent, such as external input/output, or functions that have side effects, from pure functions for internal processing, and for internal processing, purity is maintained. It is now possible to program while maintaining the I will explain this mechanism called a monad in detail in another article.
Refer to how to write functional languages
As we saw in the previous example, one feature of the purely functional language Haskell is that referential transparency is guaranteed. In other words, it consists only of functions whose return value is the same whenever the input is the same. This has the advantages mentioned above, and even in procedural languages, ​​it is possible to create programs that are reference transparent to some extent.
Be aware of referential transparency
Writing assignment statements generally causes side effects of their own. Therefore, I will try to write the Java example from earlier without using assignment statements as much as possible.
euclid
Let’s try to separate the function from the original program. The first is simply separation and the values ​​of the arguments n,m
and internal variables k
change. If you try to write a loop statement, it will be rewritten and internally there will be side effects. Rather, loop statements can be thought of as having side effects, which create a change by repeating the same command, giving it meaning. However, euclid
since it does not depend on external variables and does not rewrite external variables, euclid
it becomes a reference-transparent pure function.
Functional languages ​​use recursive calls instead of loops, so this is something you should be aware of euclid2
. This function does not assign variables, so there are no side effects, and the appearance is similar to a Haskell program. However, in detail, if
a statement is not an expression but a statement, so writing this as an expression using a ternary operator euclid3
is the most functional-like description. However, there is no need to go this far and make it look like a functional language; in practice, euclid
creating the first function will make it reference transparent, so this is sufficient.
Other characteristics of functional languages
There are other features such as higher-order functions, that is, they can take function arguments, return a function as a return value, and take type arguments. However, this is not a feature of a functional language, but rather a feature of the specifications of each language that does not depend on the type of language, so we will not specifically explain it in this article. (It is true that higher-order functions can be written in most functional languages ​​and are commonly used.)
summary
Regarding the concept of functional languages ​​used in languages ​​such as Scala, we explained what a functional language is and its characteristics.