if
- then
- else
syntax and cycles), arithmetic operators ( +
, -
, *
, /
), comparison operators ( ===
, >
, <
, and m .d.), and logical operators ( &&
, ||
,!). const multiply = (a, b) => a * b const addOne = x => x + 1 const square = x => x * x const operate = pipe( multiply, addOne, square ) operate(3, 4) // => ((3 * 4) + 1)^2 => (12 + 1)^2 => 13^2 => 169
multiply
where we used the samopisnaya function, we can take advantage of the addOne
add
function to replace our addOne
, and we can also write square
using multiply
. const square = x => multiply(x, x) const operate = pipe( multiply, add(1), square )
add(1)
very similar to the increment operator ( ++
), but the increment operator changes the variable so that it causes a mutation. As we learned from the first part , immobility is the basic principle of functional programming, so we don’t want to use ++
or its cousin --
.add(1)
and subtract(1)
to increase and decrease, but since these two operations are so common, Ramda provides inc and dec instead. const square = x => multiply(x, x) const operate = pipe( multiply, inc, square )
subtract
is a replacement for the binary operator -
, but we still have a unary operator -
to negate the value. We can also use multiply(-1)
, but Ramda provides the negate function to perform this task. const wasBornInCountry = person => person.birthCountry === OUR_COUNTRY const wasNaturalized = person => Boolean(person.naturalizationDate) const isOver18 = person => person.age >= 18 const isCitizen = either(wasBornInCountry, wasNaturalized) const isEligibleToVote = both(isOver18, isCitizen)
===
and >=
in this case). As you can imagine now, Ramda also provides substitutes for all of this.===
and gte instead of >=
. const wasBornInCountry = person => equals(person.birthCountry, OUR_COUNTRY) const wasNaturalized = person => Boolean(person.naturalizationDate) const isOver18 = person => gte(person.age, 18) const isCitizen = either(wasBornInCountry, wasNaturalized) const isEligibleToVote = both(isOver18, isCitizen)
>
, lt for <
and lte for <=
equals
there are still identical ones to determine if two values ​​are references to the same space in memory.===
: checking that a string or array is empty ( str === ''
or arr.length === 0
) and checking whether a variable is null
or undefined
. Ramda provides convenient functions for both isEmpty and isNil .both
and both
functions in the places of the operators &&
and ||
. We also talked about complement
for places with !
.wasBornInCountry
, wasNaturalized
and isOver18
all applied to the person object.&&
, ||
and !
to different values. For sub-cases, the Ramda provides us with the functions and , or and not . I think as follows: and
, or
and not
work with values, while both
, both
and complement
work with functions.||
used to get default values. For example, we can write something like this: const lineWidth = settings.lineWidth || 80
0
is a valid parameter? Since 0
is a false value, we get a line value of 80.isNil
function, which we have just learned about above, but Ramda again has a more logical option for us: defaultTo . const lineWidth = defaultTo(80, settings.lineWidth)
defaultTo
checks the second argument on isNil
. If the check fails, it returns the resulting value, otherwise it returns the first argument passed to it.forever21
, which gets the year and returns the next. But, as we are told by her name, from the age of 21, he will remain in that meaning. const forever21 = age => age >= 21 ? 21 : age + 1
age >= 21
) and the second branch ( age + 1
) can both be written as functions of age
. We can rewrite the first branch ( 21
) as a constant function ( () => 21
). Now we will have three functions that accept (or ignore) age
.if...then..else
or its shorter cousin, the ternary operator ( ?:
. const forever21 = age => ifElse(gte(__, 21), () => 21, inc)(age)
__
). We can also use lte
instead: const forever21 = age => ifElse(lte(21), () => 21, inc)(age)
age
”. I'm going to stick with the placeholder version for the rest of the post, since I find it more readable and less confusing. const forever21 = age => ifElse(gte(__, 21), always(21), inc)(age)
always(true)
and always(false)
alwaysDrivingAge
. This function takes age
and returns it if its value is gte
16. If it is less than 16, then it will return 16. This allows anyone to pretend that he controls age, even if it is not: const alwaysDrivingAge = age => ifElse(lt(__, 16), always(16), a => a)(age)
a => a
) is another typical pattern in functional programming. This is known as “identity” ( I don’t know the exact translation of the term “identity function”, just choose this one - approx. Lane ). That is, it is a function that simply returns the argument that it received. const alwaysDrivingAge = age => ifElse(lt(__, 16), always(16), identity)(age)
identity
can take more than one argument, but always returns only the first one. If we want to return something else that is different from the first argument, for this, there is a more general function nthArg . This is a much less common situation than using identity
.ifElse
expression, in which one of the logical branches is the identity, is also a typical paternum, so Ramda provides us with more reduction methods.ifElse
: const alwaysDrivingAge = age => when(lt(__, 16), always(16))(age)
gte(__, 16)
, we can use unless
. const alwaysDrivingAge = age => unless(gte(__, 16), always(16))(age)
switch
or a chain of if...then...else
expressions. const water = temperature => cond([ [equals(0), always('water freezes at 0°C')], [equals(100), always('water boils at 100°C')], [T, temp => `nothing special happens at ${temp}°C`] ])(temperature)
cond
in my code with Ramda, but I wrote similar Lisp code many years ago, so cond
feels like an old friend.forever21
, drivingAge
and water
) all accept the parameters, create a new function and then apply this function to the parameter.Source: https://habr.com/ru/post/349674/
All Articles