map
, filter
, fold
и другиПо-предния път пропуснахме темата за модели на изчисление
Колко от вас са учили СЕП?
max(3 * 4, 2 * 3)
max(12, 6)
if 12 > 6 then 12 else 6
if true then 12 else 6
12
max(3 * 4, 2 * 3)
if (3 * 4) > (2 * 3) then (3 * 4) else (2 * 3)
if (12) > (6) then (3 * 4) else (2 * 3)
if true then (3 * 4) else (2 * 3)
3 * 4
12
def describeByValue(items: List[Int], evaluation: Int): String =
if items.isEmpty then "No items available"
else s"Items: ${items.mkString(", ")} are evaluated to $evaluation"
def describeByName(items: List[Int], evaluation: => Int): String =
if items.isEmpty then "No items available"
else s"Items: ${items.mkString(", ")} are evaluated to $evaluation"
def avg(xs: List[Int]) = xs.sum / xs.size
Използвайки 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
@tailrec
Нека преправим предните примери с опашкова рекурсия
Синтаксис
Функциите са обекти, които също си имат тип.
Когато дефинираме следната функция
всъщност се дефинира обект от тип Function2
с метод apply
Function2
e нормален trait
- репрезентира функции на два аргумента
Съществуват подобни за функции на различен брой аргументи - Function0
… Function22
, FunctionXXL
Разлика между def и ламбдa?
Преобразуване от def към ламбда
Типът на 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
:
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
// Трите операции имат еднаква сложност
Immutability Changes Everything от Pat Helland
EmptyTuple
и инстанции на Tuple1
, Tuple2
, …, Tuple22
, TupleXXL
От Scala 3 имат удобни методи:
(1, "Two", 3.0).size // 3
(1, "Two", 3.0).head // 1
(1, "Two", 3.0).tail // ("Two", 3.0)
Nil *: (1, "Two", 3.0) // (List(), 1, Two, 3.0)
(0, 1) ++ (2, 3, 4) // (0, 1, 2, 3, 4)
(0, 1, 2, 3, 4).take(2) // (0, 1)
(0, 1, 2, 3, 4).drop(2) // (2, 3, 4)
(1, "Two", 3.0).toList
// val res: List[Int | (String | (Double | Nothing))] = List(1, Two, 3.0)