Перейти к содержанию

Программирование на языке 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