Программирование на языке Scala/Функции
Определения терминов
правитьФункция
правитьФу́нкцией называется соответствие между двумя множествами, при котором каждому элементу одного множества (называемого областью определения) ставится в соответствие единственный элемент другого множества (называемого множеством значений). Пример функции в математике:
y = sin(x)
Множества в Scala выражаются типами данных. Соответственно функцией в Scala можно назвать преобразование (отображение) значений одного типа данных в единственное значение того же или другого типа данных.
Соответственно, у функции есть входные параметры, одно выходное значение и алгоритм отображения.
Функции в Scala представлены в двух ипостасях, это анонимные функции (лямбда-функции) и методы класса или объекта. Методы класса или объекта будут рассмотрены позже.
Параметры функции
правитьПараметры функции определяются при создании функции, и затем используются в теле функции.
Пример:
val add: (Int, Int) => Int = (first, second) => first + second
first и second - являются параметрами функции
Аргументы функции
правитьАргументы функции указываются при вызове функции и являются значениями параметров.
Пример:
val add: (Int, Int) => Int = (first, second) => first + second
val res = add(1,2)
1 и 2 - являются аргументами функции
Анонимные функции
правитьПример функции:
(x: Int) => x + 1
где:
- (x: Int) - входной параметр функции,
- => - символ преобразования
- x + 1 - тело функции (алгоритм преобразования входного значения)
Пример другой функции с входным параметром типа Char:
(c: Char) => c.toUpper
Основное назначение анонимных функций, встраиваться в другие функции или выражения.
"abc".map((c: Char) => c.toUpper)
где map является фунцией принимающей в качестве параметра анонимную функцию.
Анонимная функция представляет собой выражение (функциональное выражение), значением которого является функция (цепочка вычислений).
Анонимной функции, как и любому выражению, можно привоить имя:
val inc = (x: Int) => x + 1
в данном случае inc указывает на функциональное выражение или функцию.
У выражения есть тип, который можно указать:
val inc: (Int) => Int = (x: Int) => x + 1
здесь (Int) => Int
- функциональный тип
Выполнить функцию или получить выходное значение функции можно указав входные аргументы функции:
// используя метод apply функционального выражения
val result1: Int = inc.apply(2)
//или используя сокращенную форму метода apply
val result2: Int = inc(2)
где:
- inc - наименование функционального выражения
- (2) - входной аргумент
Входных параметров у функции может быть несколько:
val add: (Int, Double) => Int = (x: Int, y: Double) => x + y
входящие параметры показываются списком в круглых скобках перед стрелкой: (Int, Double) =>
выходной параметр после стрелки: => Int
При отсутствии входных параметров и пустом выходящем значении получается функциональный тип () => Unit, где Unit представляет собой тип пустого множества.
val santaGo: () => Unit = () => println("ho-ho")
Основное назначение анонимных функций в Scala, встраиваться в функции высшего порядка.
Функциональные блоки выражений
правитьМожно использовать функциональный блок выражений, если тело функции состоит из нескольких выражений. Это позволяет сделать код несколько более читаемым.
// Тело функции образует одно выражение
val add: (Int, Double) => Double = (x: Int, y: Double) => x + y
// Тело функции образует блок выражений
val addAndMul: (Int, Double) => Double = (x: Int, y: Double) => {
val res1 = x + y
val res2 = x * y
res1 + res2
}
// Функция образуется из функционального блока выражений
val addAndMul2: (Int, Double) => Double = { (x: Int, y: Double) =>
val res1 = x + y
val res2 = x * y
res1 + res2
}
В функциональном блоке входящие параметры функции включены в сам блок и являются его частью. Функциональный блок позволяет упростить встраивание сложной анонимной функции в функцию высшего порядка. Подробее об этом в следующих уроках.
Функции высшего порядка
правитьФу́нкция вы́сшего поря́дка — функция, принимающая в качестве аргументов другие функции или возвращающая другую функцию в качестве результата.
Более подробное знакомство с функциями высшего порядка состоится чуть позже. Но так как для практики с анонимными функциями нам нужно использовать несколько функций высшего порядка, приведем их описание тут. В данном случае функции высшего порядка представлены методами (операциями) высшего порядка типа String.
Метод takeWhile
правитьМетод takeWhile забирает элементы из строки, пока элементы удовлетворяют условию функции.
val check: Char => Boolean =
(c: Char) => c.isUpper
"ABCd".takeWhile(check)
Результат:
ABC
Метод dropWhile
правитьМетод dropWhile удаляет элементы из строки, пока элементы удовлетворяют условию функции.
val check: Char => Boolean =
(c: Char) => c.isUpper
"ABCd".dropWhile(check)
Результат:
d
Метод foldLeft
правитьМетод foldLeft исполняет функцию для каждого элемента коллекции (символа). Метод позволяет работать с текущем элементом и накопленным значением в аккумуляторе. У метода два списка параметров, каждый список это круглые скобки. Первый список состоит из одного параметра, задающего начальное значение аккумулятора. Второй список также состоит из одного параметра, в котором указывается анонимная функция. Результат функции попадает в новое значение аккумулятора.
val summator: (Int, Char) => Int =
(acc: Int, el: Char) =>
acc + el.toInt
"123abc".foldLeft(0)(summator)
В данном примере мы посчитали сумму кодов символов всей строки. Результат:
444
Метод filterNot
правитьМетод filterNot отбрасывает элементы удовлетворяющие функции.
val checkNumber: Char => Boolean =
(c: Char) => c.isDigit
"123a".filterNot(checkNumber)
Результат:
a
Домашнее задание
править1. В учебном проекте создать файл AnonimFunction.sc (Scala-Worksheet).
2. Реализовать аналог метода contains в анонимной функции, с использованием метода indexOf
Заготовка реализации:
"abc".contains('c') // оригинальный метод
val containsFun1: (String, Char) => Boolean =
(str: String, ch: Char) =>
??? // Реализация тут
containsFun1("abc", 'b') //Проверка 1, результат true
containsFun1("abc", 'd') //Проверка 2, результат false
3. Реализовать аналог метода contains в анонимной функции, с использованием метода foldLeft
Заготовка реализации:
val containsFun2: (String, Char) => Boolean =
(str: String, ch: Char) =>
str.foldLeft(false)( (res, el) =>
??? // Реализация тут
)
containsFun2("abc", 'b') //Проверка 1, результат true
containsFun2("abc", 'd') //Проверка 2, результат false
4. Реализовать аналог метода reverse в анонимной функции, с использованием метода foldLeft
Заготовка реализации:
val reverseFun: String => String =
(str: String) =>
str.foldLeft("")((acc, el) =>
??? // Реализация тут
)
reverseFun("abc") //Проверка 1, результат cba
reverseFun("cba") //Проверка 2, результат abc
5. Реализовать аналог метода distinct в анонимной функции, с использованием метода foldLeft
Заготовка реализации:
val distinctFun: String => String =
(str: String) =>
str.foldLeft("")((acc, el) =>
??? // Реализация тут
)
distinctFun("aaa") //Проверка 1, результат a
distinctFun("abcc") //Проверка 2, результат abc
6. Реализовать аналог метода isEmpty в анонимной функции, с использованием метода foldLeft
Заготовка реализации:
val isEmptyFun: String => Boolean =
(str: String) =>
str.foldLeft(true)( (_, _) =>
??? // Реализация тут
)
isEmptyFun("") //Проверка 1, результат true
isEmptyFun("1") //Проверка 2, результат false
7. Реализовать аналог метода length в анонимной функции, с использованием метода foldLeft
Заготовка реализации:
val lengthFun: String => Int =
(str: String) =>
str.foldLeft(0)( (acc, _) =>
??? // Реализация тут
)
lengthFun("abc") //Проверка, результат 3
8. Реализовать аналог метода diff в анонимной функции, с использованием метода filterNot
Заготовка реализации:
val diffFun: (String, String) => String =
(str: String, thanStr: String) =>
??? // Реализация тут
diffFun("abc", "adef") //Проверка, результат bc
9. Реализовать аналог метода replace в анонимной функции, с использованием метода foldLeft
Заготовка реализации:
val replaceFun: (String, Char, Char) => String =
(str: String, oldChar: Char, newChar: Char) =>
str.foldLeft("")( (acc, el) =>
??? // Реализация тут
)
replaceFun("abc", 'b', 'd') //Проверка, результат adc
10. Реализовать аналог метода startsWith в анонимной функции, с использованием метода take
Заготовка реализации:
val startsWithFun: (String, String) => Boolean =
(str: String, pref: String) => {
??? // Реализация тут
}
startsWithFun("abc", "ab" ) //Проверка 1, результат true
startsWithFun("abc", "b" ) //Проверка 2, результат false
11. Реализовать аналог метода endsWith в анонимной функции, с использованием метода startsWithFun
Заготовка реализации:
val endsWithFun: (String, String) => Boolean =
(str: String, pref: String) => {
??? // Реализация тут
}
endsWithFun("abc", "bc") //Проверка 1, результат true
endsWithFun("abc", "ab") //Проверка 2, результат false
12. Реализовать функцию sortFun, с использованием методов takeWhile и dropWhile
Заготовка реализации:
val sortFun: String => String =
(str: String) =>
str.foldLeft("")( (acc, el) =>
??? // Реализация тут
)
sortFun("sdfg") //Проверка, результат dfgs