# Functions as Values — Scala

Source: https://www.geekswithgeeks.com/en/scala/c-functions

> Write lambdas, higher-order functions, currying and by-name parameters.

## Functions are first-class

Functions are values with types such as `Int => Int` or `(String, Int) => Boolean`. Write **lambdas** as `(x: Int) => x * 2` or, when the type is known, `x => x * 2`, and use the **placeholder** `_` for simple cases: `_ * 2`, `_ + _`. **Higher-order functions** take or return functions, like `map`, `filter` and your own `retry(times)(action)`. Methods (`def`) are automatically converted to function values when needed (**eta-expansion**), so `orders.map(formatOrder)` works. **Multiple parameter lists** (`def fold[B](z: B)(op: (B, A) => B)`) enable **currying**, better type inference and nice syntax for passing a block as the last argument. **By-name parameters** (`action: => A`) delay evaluating an argument until it is used, which lets you write control structures such as `retry`, `timed` or `when`. Functions **compose** with `andThen` and `compose`. **Closures** capture variables from their surrounding scope. Prefer **pure functions** (same input, same output, no side effects): they are easy to test and to run in parallel.

## Higher-order functions, currying and by-name parameters

Building a small retry helper and composing functions.

```scala
import scala.util.{Try, Success, Failure}

def retry[A](times: Int)(action: => A): Try[A] =       // action is by-name: re-evaluated each attempt
  Try(action) match
    case Failure(_) if times > 1 => retry(times - 1)(action)
    case result                  => result

var calls = 0
val result = retry(3) {
  calls += 1
  if calls < 3 then throw RuntimeException("gateway busy") else "paid"
}
println(result)                                          // Success(paid)

val addGst: BigDecimal => BigDecimal = _ * BigDecimal("1.18")
val roundRupees: BigDecimal => BigDecimal = _.setScale(2, BigDecimal.RoundingMode.HALF_UP)
val finalPrice = addGst andThen roundRupees              // function composition
println(finalPrice(BigDecimal("99.99")))                 // 117.99

def discount(percent: Int)(amount: BigDecimal): BigDecimal = amount * (100 - percent) / 100
val festive = discount(10)                              // partially applied: BigDecimal => BigDecimal
println(List(BigDecimal(100), BigDecimal(250)).map(festive))   // List(90, 225)
```

## Handing over instructions, not results

A by-name parameter is like handing someone a recipe instead of a cooked dish: they can cook it when they need it, and again if the first attempt burns.

**Quiz:** What does a by-name parameter `action: => A` do?

- [x] Delays evaluating the argument until it is used, possibly several times
- [ ] Evaluates the argument once before the call
- [ ] Makes the parameter optional
- [ ] Passes the argument by reference like C++

*Answer:* Delays evaluating the argument until it is used, possibly several times. By-name arguments are evaluated each time they are referenced inside the method.
