Лекция
Привет, Вы узнаете о том , что такое сопоставление с образцом, Разберем основные их виды и особенности использования. Еще будет много подробных примеров и описаний. Для того чтобы лучше понимать что такое сопоставление с образцом, функция высшего порядка, , настоятельно рекомендую прочитать все из категории Функциональное программирование.
Количество аргументов функции. От слов унарный, бинарный, тернарный (unary, binary, ternary) и так далее. Это необычное слово, потому что состоит из двух суффиксов: "-ary" и "-ity.". Сложение, к примеру, принимает два аргумента, поэтому это бинарная функция, или функция, у которой арность равна двум. Иногда используют термин "диадный" (dyadic), если предпочитают греческие корни вместо латинских. Функция, которая принимает произвольное количество аргументов называется, соответственно, вариативной (variadic). Но бинарная функция может принимать два и только два аргумента, без учета каррирования или частичного применения.
const sum = (a, b) => a + b
const arity = sum.length
console.log(arity) // 2
// The arity of sum is 2
Функция, которая принимает функцию в качестве аргумента и/или возвращает функцию.
const filter = (predicate, xs) => {
const result = []
for (let idx = 0; idx < xs.length; idx++) {
if (predicate(xs[idx])) {
result.push(xs[idx])
}
}
return result
}
const is = (type) => (x) => Object(x) instanceof type
filter(is(Number), [0, '1', 2, null]) // [0, 2]
Частичное применение функции означает создание новой функции с пред-заполнением некоторых аргументов оригинальной функции.
// Helper to create partially applied functions
// Takes a function and some arguments
const partial = (f, ...args) =>
// returns a function that takes the rest of the arguments
(...moreArgs) =>
// and calls the original function with all of them
f(...args, ...moreArgs)
// Something to apply
const add3 = (a, b, c) => a + b + c
// Partially applying `2` and `3` to `add3` gives you a one-argument function
const fivePlus = partial(add3, 2, 3) // (c) => 2 + 3 + c
fivePlus(4) // 9
Также в JS можно использовать Function.prototype.bind
для частичного применения функции:
const add1More = add3.bind(null, 2, 3) // (c) => 2 + 3 + c
Благодаря предварительной подготовке данных частичное применение помогает создавать более простые функции из более сложных. Функции с каррированием автоматически выполняют частичное применение.
Процесс конвертации функции, которая принимает несколько аргументов, в функцию, которая принимает один аргумент за раз.
При каждом вызове функции она принимает один аргумент и возвращает функцию, которая принимает один аргумент до тех пор, пока все аргументы не будут обработаны.
const sum = (a, b) => a + b
const curriedSum = (a) => (b) => a + b
curriedSum(40)(2) // 42.
const add2 = curriedSum(2) // (b) => 2 + b
add2(10) // 12
Трансформация функции, которая принимает несколько аргументов, в новую функцию. Если в новую функцию передать меньшее чем предусмотрено количество аргументов, то она вернет функцию, которая принимает оставшиеся аргументы. Когда функция получает правильное количество аргументов, то она исполняется.
В Underscore, lodash и ramda есть функция curry
.
const add = (x, y) => x + y
const curriedAdd = _.curry(add)
curriedAdd(1, 2) // 3
curriedAdd(1) // (y) => 1 + y
curriedAdd(1)(2) // 3
Дополнительные материалы
Соединение двух функций для формирования новой функции, в которой вывод первой функции является вводом второй.
const compose = (f, g) => (a) => f(g(a)) // Definition
const floorAndToString = compose((val) => val.toString(), Math.floor) // Usage
floorAndToString(121.212121) // '121'
Функция является чистой, если возвращаемое ей значение определяется исключительно вводными значениями, и функция не имеет побочных эффектов.
const greet = (name) => 'Hi, ' + name
greet('Brianne') // 'Hi, Brianne'
В отличие от:
let greeting
const greet = () => {
greeting = 'Hi, ' + window.name
}
greet() // "Hi, Brianne"
У функции есть побочные эффекты если кроме возврата значения она взаимодействует (читает или пишет) с внешним изменяемым состоянием.
const differentEveryTime = new Date()
console.log('IO is a side effect!')
Функция является идемпотентной если повторное ее исполнение производит такой же результат.
f(f(x)) ≍ f(x)
Math.abs(Math.abs(10))
sort(sort(sort([2, 1])))
Написание функций в таком виде, что определение не явно указывает на количество используемых аргументов. Такой стиль обычно требует каррирования или другой функции высокого порядка (или в целом — неявного программирования).
// Given
const map = (fn) => (list) => list.map(fn)
const add = (a) => (b) => a + b
// Then
// Not points-free - `numbers` is an explicit argument
const incrementAll = (numbers) => map(add(1))(numbers)
// Points-free - The list is an implicit argument
const incrementAll2 = map(add(1))
Функция incrementAll
определяет и использует параметр numbers
, так что она не использует бесточечную нотацию. incrementAll2
просто комбинирует функции и значения, не упоминая аргументов. Она использует бесточечную нотацию.
Определения с бесточечной нотацией выглядят как обычные присваивания без function
или =>
.
Предикат — это функция, которая возвращает true или false в зависимости от переданного значения. Распространенный случай использования предиката — функция обратного вызова (callback) для фильтра массива.
const predicate = (a) => a > 2
;[1, 2, 3, 4].filter(predicate) // [3, 4]
Объекты с функциями, которые подчиняются определенным правилам. Например, моноиды.
Все, что может быть присвоено переменной.
5
Object.freeze({name: 'John', age: 30}) // The `freeze` function enforces immutability.
;(a) => a
;[1]
undefined
Переменная, которую нельзя переназначить после определения.
const five = 5
const john = {name: 'John', age: 30}
Константы обладают референциальной прозрачностью или прозрачностью ссылок (referential transparency). То есть, их можно заменить значениями, которые они представляют, и это не повлияет на результат.
С константами из предыдущего листинга следующее выражение выше всегда будет возвращать true
.
john.age + five === ({name: 'John', age: 30}).age + (5)
Объект, который реализует функцию map
, которая при проходе по всем значениям в объекте создает новый объект, и подчиняется двум правилам:
// сохраняет нейтральный элемент (identity)
object.map(x => x) === object
и
// поддерживает композицию
object.map(x => f(g(x))) === object.map(g).map(f)
(f
, g
— произвольные функции)
В JavaScript есть функтор Array
, потому что он подчиняется эти правилам:
[1, 2, 3].map(x => x) // = [1, 2, 3]
и
const f = x => x + 1
const g = x => x * 2
;[1, 2, 3].map(x => f(g(x))) // = [3, 5, 7]
;[1, 2, 3].map(g).map(f) // = [3, 5, 7]
Объект с функцией of
с любым значением. В ES2015 есть Array.of
, что делает массивы указывающим функтором.
Array.of(1) //
Lifting — это когда значение помещается в объект вроде функтора. Если "поднять" (lift) функцию в аппликативный функтор, то можно заставить ее работать со значениями, которые также присутствуют в функторе.
В некоторых реализациях есть функция lift
или liftA2
, которые используются для упрощения запуска функций на функторах.
const liftA2 = (f) => (a, b) => a.map(f).ap(b)
const mult = a => b => a * b
const liftedMult = liftA2(mult) // this function now works on functors like array
liftedMult([1, 2], [3]) // [3, 6]
liftA2((a, b) => a + b)([1, 2], [3, 4]) // [4, 5, 5, 6]
Подъем функции с одним аргументом и ее применение выполняет то же самое, что и map
.
const increment = (x) => x + 1
lift(increment)([2]) // [3]
;[2].map(increment) // [3]
Если выражение можно заменить его значением без влияния на поведение программы, то оно обладает прозрачностью ссылок.
Например, есть функция greet
:
const greet = () => 'Hello World!'
Любой вызов greet()
можно заменить на Hello World!
, так что эта функция является прозрачной (referentially transparent).
Анонимная функция, которую можно использовать как значение.
;(function (a) {
return a + 1
})
;(a) => a + 1
Лямбды часто передают в качестве аргументов в функции высокого порядка.
[1, 2].map((a) => a + 1) // [2, 3]
Лямбду можно присвоить переменной.
const add1 = (a) => a + 1
Область информатики, в которой функции используются для создания универсальной модели исчисления.
Механизм вычисления при необходимости, с задержкой вычисления выражения до того момента, пока значение не потребуется. В функциональных языках это позволяет создавать структуры вроде бесконечных списков, которые в обычных условиях невозможны в императивных языках программирования, где очередность команд имеет значение.
const rand = function*() {
while (1 < 2) {
yield Math.random()
}
}
const randIter = rand()
randIter.next() // Каждый вызов дает случайное значение, выражение исполняется при необходимости.
Объект с функцией, которая "комбинирует" объект с другим объектом того же типа. Простой пример моноида это сложение чисел:
1 + 1 // 2
В этом случае число — это объект, а +
это функция.
Должен существовать нейтральный элемент (identity), так, чтобы комбинирование значения с ним не изменяло значение. В случае сложения таким элементом является 0
.
1 + 0 // 1
Также необходимо, чтобы группировка операций не влияла на результат (ассоциативность):
1 + (2 + 3) === (1 + 2) + 3 // true
Конкатенация массивов — это тоже моноид:
;[1, 2].concat([3, 4]) // [1, 2, 3, 4]
Нейтральный элемент — это пустой массив []
;[1, 2].concat([]) // [1, 2]
Если существуют функции нейтрального элемента и композиции, то функции в целом формируют моноид:
const identity = (a) => a
const compose = (f, g) => (x) => f(g(x))
foo
— это любая функция с одним аргументом.
compose(foo, identity) ≍ compose(identity, foo) ≍ foo
Монада — это объект с функциями of
и chain
. chain
похож на map
, но он производит разложение вложенных объектов в результате.
// Implementation
Array.prototype.chain = function (f) {
return this.reduce((acc, it) => acc.concat(f(it)), [])
}
// Usage
;Array.of('cat,dog', 'fish,bird').chain((a) => a.split(',')) // ['cat', 'dog', 'fish', 'bird']
// Contrast to map
;Array.of('cat,dog', 'fish,bird').map((a) => a.split(',')) // [['cat', 'dog'], ['fish', 'bird']]
of
также известен как return
в других функциональных языках.
chain
также известен как flatmap
и bind
в других языках.
Объект с функциями extract
и extend
.
const CoIdentity = (v) => ({
val: v,
extract () {
return this.val
},
extend (f) {
return CoIdentity(f(this))
}
})
Extract берет значение из функтора.
CoIdentity(1).extract() // 1
Extend выполняет функцию на комонаде. Функция должна вернуть тот же тип, что комонада.
CoIdentity(1).extend((co) => co.extract() + 1) // CoIdentity(2)
Объект с функцией ap
. ap
применяет функцию в объекте к значению в другом объекте того же типа.
// Implementation
Array.prototype.ap = function (xs) {
return this.reduce((acc, f) => acc.concat(xs.map(f)), [])
}
// Example usage
;[(a) => a + 1].ap([1]) //
Это полезно, когда есть два объекта, и нужно применить бинарную операцию на их содержимом.
// Arrays that you want to combine
const arg1 = [1, 3]
const arg2 = [4, 5]
// combining function - must be curried for this to work
const add = (x) => (y) => x + y
const partiallyAppliedAdds = [add].ap(arg1) // [(y) => 1 + y, (y) => 3 + y]
В итоге получим массив функций, которые можно вызвать с ap
чтобы получить результат:
partiallyAppliedAdds.ap(arg2) // [5, 6, 7, 8]
Функция трансформации.
Функция, у которой ввод и вывод — одного типа.
// uppercase :: String -> String
const uppercase = (str) => str.toUpperCase()
// decrement :: Number -> Number
const decrement = (x) => x - 1
Пара структурных трансформаций между двумя типами объектов без потери данных.
Например, двумерные координаты можно хранить в массиве [2,3]
или объекте {x: 2, y: 3}
.
// Providing functions to convert in both directions makes them isomorphic.
const pairToCoords = (pair) => ({x: pair[0], y: pair[1]})
const coordsToPair = (coords) => [coords.x, coords.y]
coordsToPair(pairToCoords([1, 2])) // [1, 2]
pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2}
Объект, у которого есть функция equals
, которую можно использовать для сравнения объектов одного типа.
Сделать массив сетоидом:
Array.prototype.equals = (arr) => {
const len = this.length
if (len !== arr.length) {
return false
}
for (let i = 0; i < len; i++) {
if (this[i] !== arr[i]) {
return false
}
}
return true
}
;[1, 2].equals([1, 2]) // true
;[1, 2].equals([0]) // false
Объект с функцией concat
, которая комбинирует его с другим объектом того же типа.
;[1].concat([2]) // [1, 2]
Объект, в котором есть функция reduce
, которая трансформирует объект в другой тип.
const sum = (list) => list.reduce((acc, val) => acc + val, 0)
sum([1, 2, 3]) // 6
Часто функции в JavaScript содержат комментарии с указанием типов их аргументов и возвращаемых значений. Об этом говорит сайт https://intellect.icu . В сообществе существуют разные подходы, но они все схожи:
// functionName :: firstArgType -> secondArgType -> returnType
// add :: Number -> Number -> Number
const add = (x) => (y) => x + y
// increment :: Number -> Number
const increment = (x) => x + 1
Если функция принимает другую функцию в качестве аргумента, то ее помещают в скобки.
// call :: (a -> b) -> a -> b
const call = (f) => (x) => f(x)
Символы a
, b
, c
, d
показывают, что аргументы могут быть любого типа. Следующая версия функции map
принимает:
a
в другой тип b
a
,
и возвращает массив значений типа b
.
// map :: (a -> b) -> [a] -> [b]
const map = (f) => (list) => list.map(f)
Дополнительные материалы
Комбинация двух типов в один, новый тип.
В JavaScript нет статических типов, но давайте представим, что мы изобрели тип NumOrString
, который является сложением String
и Number
.
Операция +
в JavaScript работает со строками и числами, так что можно использовать наш новый тип для описания его ввода и вывода:
// add :: (NumOrString, NumOrString) -> NumOrString
const add = (a, b) => a + b
add(1, 2) // Возвращает число 3
add('Foo', 2) // Возвращает строку "Foo2"
add('Foo', 'Bar') // Возвращает строку "FooBar"
Тип-объединение также известно как алгебраический тип, размеченное объединение и тип-сумма.
Существует пара библиотек в JavaScript для определения и использования таких типов.
Тип-произведение комбинирует типы таким способом, который вам скорее всего знаком:
// point :: (Number, Number) -> {x: Number, y: Number}
const point = (x, y) => ({x: x, y: y})
Его называют произведением, потому что возможное значение структуры данных это произведение (product) разных значений.
Вау!! 😲 Ты еще не читал? Это зря!: теория множеств.
Тип-объединение с двумя случаями: Some
и None
. Полезно для композиции функций, которые могут не возвращать значения.
// Naive definition
const Some = (v) => ({
val: v,
map (f) {
return Some(f(this.val))
},
chain (f) {
return f(this.val)
}
})
const None = () => ({
map (f) {
return this
},
chain (f) {
return this
}
})
// maybeProp :: (String, {a}) -> Option a
const maybeProp = (key, obj) => typeof obj[key] === 'undefined' ? None() : Some(obj[key])
Используйте chain
для построения последовательности функций, которые возвращают Option
.
// getItem :: Cart -> Option CartItem
const getItem = (cart) => maybeProp('item', cart)
// getPrice :: Item -> Option Number
const getPrice = (item) => maybeProp('price', item)
// getNestedPrice :: cart -> Option a
const getNestedPrice = (cart) => getItem(obj).chain(getPrice)
getNestedPrice({}) // None()
getNestedPrice({item: {foo: 1}}) // None()
getNestedPrice({item: {price: 9.99}}) // Some(9.99)
Option
также известен как Maybe
. Some
иногда называют Just
. None
иногда называют Nothing
.
Сопоставление с образцом (англ. pattern matching) — метод анализа и обработки структур данных в языках программирования, основанный на выполнении определенных инструкций в зависимости от совпадения исследуемого значения с тем или иным образцом, в качестве которого может использоваться константа, предикат, тип данных или иная поддерживаемая языком конструкция.
Как правило, имеется возможность указать более одного образца и связанного с ним действия.
Сопоставление с образцом часто встречается в функциональных языках программирования, таких как языки семейства ML и Haskell, в том числе в виде охранных выражений.
Образцы последовательностей (например, текстовая строка) можно сопоставлять с регулярными выражениями.
Простейшим вариантом является сопоставление с константой. В этом случае сопоставление с образцом эквивалентно условному оператору или конструкции «switch» («case») в императивных языках.
Рассмотрим, для примера, вычисление логического отрицания.
В OCaml:
let neg x =
match x with
| false -> true
| true -> false
;;
Здесь следующие за символом "|" значения являются образцами, а следующие за «->» выражения вычисляются при совпадении аргумента «x» с одним из образцов.
Тот же пример с использованием условного оператора:
let neg x =
if x = false then true
else false
;;
Нахождение суммы списка:
let rec sum l =
match l with
| [] -> 0
| x :: xs -> x + (sum xs)
;;
В этом примере аргумент функции «sum» сопоставляется со значением «пустой список» либо с образцом «голова :: хвост» (где «::» — оператор добавления элемента в начало списка).
В качестве образца может применяться конструктор значения типа:
type animal = Dog of string | Cat of string ;;
let say x =
match x with
| Dog (x) -> x ^ "says 'woof'"
| Cat (x) -> x ^ "says 'meow'"
;;
Языки с развитыми средствами обработки текста, такие как AWK и SNOBOL, поддерживают сопоставление с регулярным выражением.
Пример на AWK, подсчет количества включений слов «foo» или «bar»:
/foo|bar/ { foobar++ }
END { print foobar }
Объектами первого класса (англ. first-class object, first-class entity, first-class citizen) в контексте конкретного языка программирования называются элементы, которые могут быть переданы как параметр, возвращены из функции, присвоены переменной .
Понятие объектов первого и второго классов было предложено в 1967 г. Кристофером Стрэчи в статье «Understanding Programming Languages», где процедуры языка Алгол, в противоположность действительным числам, он сравнил с подвергающимися социальной дискриминации «людьми второго сорта» (англ. second-class citizens) .
Объект называют «объектом первого класса», если он :
Термин «объект» используется здесь в общем смысле и не ограничивается объектами языка программирования. Так, значения простейших типов данных, например, integer и float, во многих языках являются «объектами первого класса».
В C и C++ нельзя создавать функции во время выполнения программы, поэтому функции не являются объектами первого класса в этих языках. В то же время указатели на функцию можно передавать в качестве аргумента и возвращать из другой функции, поэтому иногда функции в C++ называют объектами второго класса (англ. second-class object). Тем не менее, в C++ есть понятие функционального объекта (англ. function object), который является объектом первого класса и реализует эквивалентную функциям семантику .
В Smalltalk , Scala, и JavaScript функции (методы) и классы являются объектами первого класса. Поскольку операторы (+
, -
) в Smalltalk по сути методы, они также являются объектами первого класса.
Пример кода на языке Nim.
# присвоим процедуру переменной
var value = proc() =
echo "value"
value() # вызов процедуры
var value2 = value
value2() # вызов процедуры
# процедура будет передана другой
proc two(): string =
return "two"
# процедура будет получать другую процедуру
proc wrap(x: proc) =
echo "one"
echo x()
echo "three"
# вызов процедуры которая получает на вход другую процедуру
wrap(two)
# процедура, которая возвращает процедуру
proc closure(x: int): proc =
proc res(y:int): int =
return y*y+x
return res
var result = closure(2) # вызовем процедуру которая вернет другую процедуру
echo result(3) # вызов внутренней процедуры
Перейти к навигацииПерейти к поиску
Фу́нкция вы́сшего поря́дка — в программировании функция, принимающая в качестве аргументов другие функции или возвращающая другую функцию в качестве результата. Основная идея состоит в том, что функции имеют тот же статус, что и другие объекты данных. Использование функций высшего порядка приводит к абстрактным и компактным программам, принимая во внимание сложность производимых ими вычислений.
Следующий исходный код, написанный на Python, содержит функцию высшего порядка g(), которая в качестве первого аргумента принимает функцию. В результате на экран будет выведено «100» (результат вычисления (7+3)×(7+3)).
def f(x):
return x + 3
def g(function, x):
return function(x) * function(x)
print (g(f, 7))
Та же программа на F#, здесь g — функция высшего порядка, принимающая функцию func в качестве параметра.
let f x = x + 3
let g func x = (func x) * (func x)
System.Console.WriteLine(g f 7)
На C#, здесь g — функция высшего порядка, принимающая функцию func в качестве параметра.
var f = (Func<int, int>)((x) => x + 3);
var g = (Func<Func<int, int>, int, int>)((func, x) => func(x) * func(x));
Console.WriteLine(g(f, 7));
Тот же код, написанный на языке Ruby.
Вариант 1. Использования lambda-объекта.
f = ->(x) { x+3 }
def g (f, x); f.call( x ) * f.call( x ) end
puts g f,7
Вариант 2. Использование блока для подстановки анонимной функции.
def g x; (yield x) * (yield x) end
puts g(7){|x| x+3}
На языке Elixir
defmodule Hop do
def twice(f, v) do
f.(f.(v))
end
end
add3 = fn(v) -> 3 + v end
IO.puts Hop.twice(add3, 7) #13
На Erlang
f(X) ->
X + 3.
g(Fun, X) ->
Fun(X) * Fun(X).
start()->
Result = g(fun f/1, 7),
io:format("~p", [Result]).
На Pascal.
{$mode objfpc}
type fun = function(x:integer):integer;
function f(x:integer):integer;
begin
f:= x+3;
end;
function g( func:fun; x:integer):integer;
begin
g:= func(x)*func(x);
end;
begin
write(g(@f, 7));
end.
На PHP.
<?php
$f = function (int $x): int {
return $x + 3;
};
function g(callable $function, int $x): int
{
return $function($x)*$function($x);
}
print g($f, 7);
На Clojure.
(defn g [f x]
(* (f x) (f x)))
(print (g #(+ 3 %) 7))
На Lua.
local f = function(func, x)
return func(x) * func(x)
end
print(f(function(x) return x + 3 end, 7))
То же самое на Haskell.
f func x = (func x)^2
main = print $ f (+3) 7
На Scala.
Вариант 1. С использованием обычной функции:
def f(x: Int) = x + 3
def g(f: Int ⇒ Int, x: Int) = f(x) * f(x)
println(g(f, 7))
Вариант 2. С использованием анонимной функции:
def g(f: Int ⇒ Int, x: Int) = f(x) * f(x)
println(g(_ + 3, 7))
На Perl:
my $f=sub { $_[0]+3 };
sub g {
$_[0]->($_[1])*$_[0]->($_[1])
}
say g $f,7
На JavaScript
// ES5
var f = function (x) {
return x + 3;
};
var g = function (func, x) {
return func(x) * func(x);
};
console.log(g(f, 7));
// ES6
let f = x => x + 3;
let g = (func, x) => func(x) * func(x);
console.log(g(f, 7));
На языке Swift.
Вариант 1. С использованием обычной функции.
func f(_ x: Int) -> Int {
return x + 3
}
func g(_ function: (Int) -> Int, x: Int) -> Int {
return function(x) * function(x)
}
print(g(f, x: 7))
Вариант 2. С использованием анонимной функции:
let g: (Int, (Int) -> Int) -> Int = { (x, f) in f(x) * f(x) }
print(g(7) { x in x + 3 })
// С сокращенными именами параметров
let g: (Int, (Int) -> Int) -> Int = { $1($0) * $1($0) }
print(g(7) { $0 + 3 })
на nim
proc f(x: int): int =
return x + 3
proc g(function: proc, x: int): int =
return function(x) * function(x)
echo g(f, 7)
И на Java
Function<Integer, Integer> f = x -> x + 3;
BiFunction<Function<Integer, Integer>, Integer, Integer> g = (func, x) -> func.apply(x) * func.apply(x);
System.out.println(g.apply(f, 7));
На Groovy
f = { x -> x + 3 }
g = { func, x -> func(x) * func(x) }
System.out.println(g(f, 7))
На C
int f(int x){ return x + 3; }
int g(int (*func)(int), int x){ return func(x) * func(x); }
printf("%d", g(f, 7));
На C++
int f(int x){ return x + 3; }
template<typename T>
int g(T&& func, int x){ return func(x) * func(x); }
std::cout << g(f, 7);
На C++ с использованием лямбда-функций
auto f = [](auto x){ return x + 3; }
auto g = [](auto f, auto x){ return f(x) * f(x); }
std::cout << g(f, 7);
На Scheme
(define (f x)(+ x 3))
(define (g f x)(* (f x) (f x)))
(print (g f 7))
На Kotlin
fun f(x:Int):Int= x+3
fun g(function:(y:Int)->Int, x:Int):Int = function(x)*function(x)
println(g(::f,7))
На Go
func f(x int) int {
return x + 3
}
func g(function func(x int) int, x int) int {
return function(x) * function(x)
}
fmt.Print(g(f, 7))
На Bash
#! /bin/bash
function f(){
X=$1;
echo $(( $X + 3 ));
}
function g(){
FUNCTION=$1;
X=$2;
echo $(( $( ${FUNCTION} ${X} ) * $( ${FUNCTION} ${X} ) ));
}
echo "$( g f 7 )";
Исследование, описанное в статье про сопоставление с образцом, подчеркивает ее значимость в современном мире. Надеюсь, что теперь ты понял что такое сопоставление с образцом, функция высшего порядка, и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Функциональное программирование
Комментарии
Оставить комментарий
Функциональное программирование
Термины: Функциональное программирование