Scala's functional programming features let you write expressive, composable, and testable code. Functions are first-class values that can be passed, returned, and combined.
Functions as Values
Scala
// Function type: (input) => output
val double: Int => Int = _ * 2
val greet: String => String = name => s"Hello, $name!"
// Higher-order functions
def applyToAll[A, B](list: List[A], f: A => B): List[B] = list.map(f)
applyToAll(List(1, 2, 3), double) // List(2, 4, 6)
applyToAll(List("a", "b"), _.toUpperCase) // List("A", "B")
// Partial application
def add(a: Int, b: Int): Int = a + b
val add5 = add(5, _: Int) // Int => Int
add5(3) // 8
// Currying
def multiply(a: Int)(b: Int): Int = a * b
val triple = multiply(3) _ // Int => Int
triple(4) // 12Immutability Patterns
Scala
// Immutable data structures
val list = List(1, 2, 3)
val newList = list :+ 4 // List(1, 2, 3, 4)
val filtered = list.filter(_ > 1) // List(2, 3)
// Builder pattern with immutable state
case class Config(
host: String = "localhost",
port: Int = 8080,
debug: Boolean = false,
timeout: Int = 30
)
val productionConfig = Config(host = "prod.example.com", port = 443)
val debugConfig = productionConfig.copy(debug = true, port = 8080)
// Fold to transform data
val words = List("hello", "world", "scala")
val lengthMap = words.foldLeft(Map.empty[String, Int]) { (map, word) =>
map + (word -> word.length)
}
// Map("hello" -> 5, "world" -> 5, "scala" -> 5)Composing Functions
Scala
// Function composition
val trim: String => String = _.trim
val lowercase: String => String = _.toLowerCase
val removeSpaces: String => String = _.replaceAll("\\s", "-")
// Compose: (f ∘ g)(x) = f(g(x))
val normalize = trim andThen lowercase andThen removeSpaces
normalize(" Hello World ") // "hello-world"
// Pipe operator style
def pipe2[A, B, C](f: A => B, g: B => C): A => C = f andThen g
// Lift: wrap a function to work on Option
def lift[A, B](f: A => B): Option[A] => Option[B] = _.map(f)
val safeDouble: Option[Int] => Option[Int] = lift((x: Int) => x * 2)
safeDouble(Some(5)) // Some(10)
safeDouble(None) // NoneFor Comprehensions (Desugared)
Scala
// For comprehension
for {
x <- List(1, 2, 3)
y <- List(10, 20)
} yield x + y
// Desugars to:
List(1, 2, 3).flatMap(x => List(10, 20).map(y => x + y))
// List(11, 12, 21, 22, 31, 32)
// With guards
for {
x <- List(1, 2, 3, 4, 5)
if x % 2 == 0
} yield x * x
// List(4, 16)
// Chained for-comprehensions with Option
def lookupUser(id: Int): Option[User] = ???
def getOrders(user: User): Option[List[Order]] = ???
def getTotal(order: Order): Option[Double] = ???
val total: Option[Double] = for {
user <- lookupUser(1)
orders <- getOrders(user)
order <- orders.headOption
total <- getTotal(order)
} yield totalMonads in Scala
Scala
// Option, List, Try, Either, Future are all monads
// They share: flatMap, map, filter, fold
// Option monad (handles nullability)
val result: Option[Int] = for {
a <- Some(10)
b <- Some(5)
} yield a - b
// Some(5)
// Either monad (handles errors)
def parse(s: String): Either[String, Int] =
Either.cond(s.forall(_.isDigit), s.toInt, s"$s is not a number")
val sum: Either[String, Int] = for {
a <- parse("10")
b <- parse("5")
} yield a + b
// Right(15)
// Future monad (handles async)
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
val userData: Future[User] = for {
user <- fetchUser(id)
orders <- fetchOrders(user.id)
} yield user.copy(recentOrders = orders)Tail Recursion
Scala
import scala.annotation.tailrec
// Tail-recursive factorial
@tailrec
def factorial(n: Int, acc: Int = 1): Int =
if (n <= 1) acc
else factorial(n - 1, n * acc)
factorial(10) // 3628800
// Tail-recursive Fibonacci
@tailrec
def fibonacci(n: Int, a: Int = 0, b: Int = 1): Int =
if (n == 0) a
else fibonacci(n - 1, b, a + b)
fibonacci(10) // 55
// Tail-recursive list processing
@tailrec
def sumList(list: List[Int], acc: Int = 0): Int = list match {
case Nil => acc
case head :: tail => sumList(tail, acc + head)
}💡 Tip: Use
.foldLeftor.foldRightinstead of var loops. They're safer (no state bugs), composable, and often more readable.