map
, filter
, fold
и другиИзползвайки substitution model
fact(5)
--
5 * fact(5 - 1) =
--
5 * fact(4) =
--
5 * (4 * fact(4 - 1)) =
--
5 * (4 * fact(3)) =
--
5 * (4 * (3 * fact(3 - 1))) =
--
5 * (4 * (3 * fact(2))) =
--
5 * (4 * (3 * (2 * fact(2 - 1)))) =
--
5 * (4 * (3 * (2 * fact(1)))) =
--
5 * (4 * (3 * (2 * 1)))
ако извикаме функцията с Int.MaxValue
ще получим java.lang.StackOverflowError
“A recursive function is tail recursive when recursive call is the last thing executed by the function.”
fact(5, 1)
--
fact(5 - 1, 5 * 1) =
--
fact(4, 5) =
--
fact(4 - 1, 5 * 4) =
--
fact(3, 20) =
--
fact(3 - 1, 20 * 3) =
--
fact(2, 60) =
--
fact(2 - 1, 60 * 2) =
--
fact(1, 120) =
--
120
Нека преправим предните примери с опашкова рекурсия
case class Person(name: String, age: Int, address: Address)
case class Address(country: String, city: String, street: String)
def getOlder(person: Person): Person = person.copy(age = person.age + 1)
val youngRadost = Person("Radost", 24, Address("Bulgaria", "Veliko Tarnovo", "ul. Roza"))
val olderRadost = getOlder(radost)
Неизменимосттa ни позволява:
youngRadost
и olderRadost
) остават валидниcase class Person(name: String, age: Int, address: Address)
case class Address(country: String, city: String, street: String)
def getOlder(person: Person): Person = person.copy(age = person.age + 1)
val youngRadost = Person("Radost", 24, Address("Bulgaria", "Veliko Tarnovo", "ul. Roza"))
val olderRadost = getOlder(radost)
Тук вече няма как да споделим общите елементи
балансирано дърво
val v1 = Vector(1, 2, 3, 4, 5, 6, 7)
v1.head // 1
v1.last // 7
v1(4) // 5
// Трите операции имат еднаква сложност
Синтаксис
Функциите са обекти, които също си имат тип.
Когато дефинираме следната функция
всъщност се дефинира обект от тип Function2
с метод apply
Function2
e нормален trait
- репрезентира функции на два аргумента
Съществуват подобни за функции на различен брой аргументи - Function0
… Function22
Преобразуване на метод към функция
Типът на addOne
е Int => Int
Дефиниция - Функции, които приемат функции като параметри или връщат функции като резултат
List(1, 2, 3).map(_ * 2)
// res0: List[Int] = List(2, 4, 6)
List("foo", "bar", "baz").map(wrapWithDiv)
//res1: List[String] = List("<div>foo</div>", "<div>bar</div>", "<div>baz</div>")
List(1, -5, 6, -20).map(_.abs)
//res12: List[Int] = List(1, 5, 6, 20)
List(1, 2, 3).map(sum(_, 1))
//res11: List[Int] = List(2, 3, 4)
mapSL
Scala не може да определи типа на n
, тъй като не знае типа на A
mapML
:
A
A
вече е фиксиран, което позволява да се определи B
currying е преобразуването на функция с много параметри към последователност от функции, всяка приемаща един параметър
кръстено на Haskell Curry
алтернатива на частично приложените функции
И при двата случая isEvenLen
изразява s => even(len(s))
Scala 3 прави последното автоматично без нужда от tupled