Let’s not rush into the new concepts that we have planned in this article. In the opening section here we will talk about some elements related to the concepts in the previous lesson. First we’ll talk about variables created in binding
syntaxes like let .. in
.
Although Functional
languages are all designed with strict data-typing characteristics. However, the generated variables will all have implicit data types and the compiler will automatically find information from the value assigned to each variable. And then to ensure consistency and rigor in the code logic, the Variables in the default Functional Programming
-specific design environment are left unchanged.
This means that Variables in Functional
environments like Elm
, Haskell
, PureScript
, are functionally equivalent to constant
in other programming environments. Even in the operation of defining functions, the elements to the left of the =
symbol, including the function naming variable and input parameters, are immutable
elements. The concept of immutable
and side-effect
is used a lot in the Functional
environment and we will note it from here.
1 2 3 4 5 6 | elm repl ---- Elm 0.19.1 ---------------------------------------------------------------- Say :help for help and :exit to exit! More at <https://elm-lang.org/0.19.1/repl> -------------------------------------------------------------------------------- > _ |
Higher-Order Function
Higher-Order Functions are roughly understood as Functions with a higher observation position.
For example, when we pass a Function g
into the call of Function f
and then the logic operating inside Function f
will make the call of Function g
to delegate some work. Now Function f
is considered as Higher-Order Function
compared to Function g
; Because f
already knows information about g
through parameter types, and g
knows nothing about f
.
1 2 3 | > List.map not [True, False] > [False,True] : List Bool |
In the above example, we passed the not
function into the map
module List
, and delegated the inverse of the Bool
values inside the passed List
in the next parameter position. Thus List.map
at least knows that the function passed in the first argument of the form (a -> b)
converts the value of an element in the List
. And the operation logic of List.map
is to call the not
function with each element of List
in turn to obtain new values and create a completely new List
of results.
We can also use lambda
Anonymous Function expressions that are syntactically similar to JavaScript
to pass to List.map
. In this case, Elm
will implicitly assume the data type of the input parameter to the Anonymous Function is the type of the data in the List
, and the returned result will depend on the logic inside the lambda
.
1 2 3 4 5 6 | > List.map (n -> n * 9) (List.range 0 9) [0,9,18,27,36,45,54,63,72,81] : List Int > (n -> n * 9) <function> : number -> number |
And this is how JavaScript
has built-in HOD
support for coders to use with the map
method of Array
arrays.
1 2 3 4 5 | <span class="token keyword">var</span> origin <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token number">2</span> <span class="token punctuation">,</span> <span class="token number">3</span> <span class="token punctuation">,</span> <span class="token number">4</span> <span class="token punctuation">,</span> <span class="token number">5</span> <span class="token punctuation">,</span> <span class="token number">6</span> <span class="token punctuation">,</span> <span class="token number">7</span> <span class="token punctuation">,</span> <span class="token number">8</span> <span class="token punctuation">,</span> <span class="token number">9</span> <span class="token punctuation">]</span> <span class="token keyword">var</span> nile <span class="token operator">=</span> origin <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">n</span> <span class="token punctuation">)</span> <span class="token operator">=></span> n <span class="token operator">*</span> <span class="token number">9</span> <span class="token punctuation">)</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> nile <span class="token punctuation">)</span> |
The concept of Higher-Order Function
can also be expressed in another case, when Function f
returns a value of a Function g
. At this time, f
is also considered as a function with a higher observation angle than g
. However, for a descriptive example, we will move on to the next related concept, Currying Function
.
Currying Function
In Elm
‘s REPL
window, let’s try to check the type information of List.map
, because we already know the Higher-Order Function
and maybe there will be times when we want to define such a HOD
function ourselves.
1 2 3 | > List.map <function> : (a -> b) -> List a -> List b |
So we have List.map
which is a function <function>
, which takes the first parameter a function (a -> b)
, and the second parameter a list List a
, and returns the result. is a new List b
. However, we can also read the type information of List.map
with the following parameter and the results are grouped by parentheses ()
like this:
1 2 | <function> : (a -> b) -> (List a -> List b) |
That means List.map
is a function <function>
, which takes a function (a -> b)
as a parameter and returns a new function (List a -> List b)
. So we can understand List.map
is also the Higher-Order Function
of the function (List a -> List b)
.
Now from the perspective of using the List.map
function, we will be able to create a new function (List a -> List b)
and then use this function for different List
.
1 2 3 4 5 6 7 8 9 | > kyudo = List.map (n -> n * 9) <function> : List number -> List number > kyudo (List.range 0 9) [0,9,18,27,36,45,54,63,72,81] : List Int > kyudo [0,10,20,30,40,50,60,70,80,90] [0,90,180,270,360,450,540,630,720,810] : List number |
Thus List.map
was used by applying partial application
parameters, instead of parameters being passed in at the same time in a function call. And manipulating the function definition with such layered parameters so that we can then partially apply it is called Currying Function
.
In many functional programming languages including Elm
and Haskell
, and the PureScript
, the function definition syntax automates Currying
. In other languages, if the syntax is not supported, we will have to write a bit more verbose, for example, JavaScript
before the lambda
syntax. As for languages that support lambda
syntax, we only need to lambda
single-parameter lambdas.
1 2 3 4 5 6 7 8 9 10 | <span class="token comment">// -- map : (a -> b) -> (Array a -> Array b)</span> <span class="token keyword">function</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">f</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">$array</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* ... */</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// -- map : (a -> b) -> (Array a -> Array b)</span> <span class="token keyword">const</span> <span class="token parameter">map</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token parameter">f</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token parameter">$array</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">/* ... */</span> <span class="token punctuation">}</span> |
However, if we were to define an Array.map
function like this ourselves in JavaScript
, we would obviously need to use Imperative
elements like creating an empty result array and updating it through loops. The important point that we need to note is that the original $array
should not be changed in content after any operation.