Claude
Skills
Sign in
Back

Scala Functional Patterns

Included with Lifetime
$97 forever

Use when functional programming patterns in Scala including higher-order functions, immutability, pattern matching, algebraic data types, monads, for-comprehensions, and functional composition for building robust, type-safe applications.

General

What this skill does


# Scala Functional Patterns

## Introduction

Scala uniquely blends object-oriented and functional programming paradigms,
enabling developers to leverage the best of both worlds. Functional programming
in Scala emphasizes immutability, pure functions, and composability, leading to
more predictable and maintainable code.

Core functional patterns in Scala include higher-order functions, immutable data
structures, pattern matching, algebraic data types (ADTs), monadic composition,
for-comprehensions, and type classes. These patterns enable elegant solutions to
complex problems while maintaining type safety.

This skill covers immutability principles, higher-order functions, pattern
matching, ADTs with sealed traits, Option and Either monads, for-comprehensions,
function composition, and functional error handling.

## Immutability and Pure Functions

Immutable data structures and pure functions form the foundation of functional
programming, ensuring predictable behavior and thread safety.

```scala
// Immutable case classes
case class User(
  id: Int,
  name: String,
  email: String,
  age: Int
)

// Copying with modifications
val user = User(1, "Alice", "[email protected]", 30)
val updatedUser = user.copy(age = 31)

// Immutable collections
val numbers = List(1, 2, 3, 4, 5)
val doubled = numbers.map(_ * 2)  // Original list unchanged

// Pure functions (deterministic, no side effects)
def add(a: Int, b: Int): Int = a + b

def multiply(a: Int, b: Int): Int = a * b

def calculateTotal(price: Double, quantity: Int, discount: Double): Double = {
  val subtotal = price * quantity
  val discountAmount = subtotal * discount
  subtotal - discountAmount
}

// Impure function (side effect: logging)
def impureAdd(a: Int, b: Int): Int = {
  println(s"Adding $a and $b")  // Side effect
  a + b
}

// Separating pure logic from side effects
def pureCalculation(items: List[Double]): Double =
  items.sum

def displayResult(result: Double): Unit =
  println(s"Total: $result")

val items = List(10.0, 20.0, 30.0)
val total = pureCalculation(items)
displayResult(total)

// Immutable data transformations
case class Order(items: List[String], total: Double)

def addItem(order: Order, item: String, price: Double): Order =
  order.copy(
    items = order.items :+ item,
    total = order.total + price
  )

def applyDiscount(order: Order, percentage: Double): Order =
  order.copy(total = order.total * (1 - percentage))

// Composing immutable transformations
val order = Order(List("Book"), 25.0)
val finalOrder = applyDiscount(addItem(order, "Pen", 5.0), 0.1)

// Immutable builder pattern
case class PersonBuilder(
  name: Option[String] = None,
  age: Option[Int] = None,
  email: Option[String] = None
) {
  def withName(n: String): PersonBuilder = copy(name = Some(n))
  def withAge(a: Int): PersonBuilder = copy(age = Some(a))
  def withEmail(e: String): PersonBuilder = copy(email = Some(e))

  def build: Option[Person] = for {
    n <- name
    a <- age
    e <- email
  } yield Person(n, a, e)
}

case class Person(name: String, age: Int, email: String)

val person = PersonBuilder()
  .withName("Bob")
  .withAge(25)
  .withEmail("[email protected]")
  .build
```

Immutability eliminates entire classes of bugs related to shared mutable state
and enables safe concurrent programming.

## Higher-Order Functions

Higher-order functions accept functions as parameters or return functions,
enabling powerful abstraction and code reuse.

```scala
// Functions as parameters
def applyOperation(x: Int, y: Int, op: (Int, Int) => Int): Int =
  op(x, y)

val sum = applyOperation(5, 3, (a, b) => a + b)
val product = applyOperation(5, 3, (a, b) => a * b)

// Functions as return values
def multiplyBy(factor: Int): Int => Int =
  (x: Int) => x * factor

val double = multiplyBy(2)
val triple = multiplyBy(3)

println(double(5))  // 10
println(triple(5))  // 15

// Currying
def curriedAdd(a: Int)(b: Int): Int = a + b

val add5 = curriedAdd(5) _
println(add5(3))  // 8

// Partial application
def greet(greeting: String, name: String): String =
  s"$greeting, $name!"

val sayHello: String => String = greet("Hello", _)
println(sayHello("Alice"))  // Hello, Alice!

// Function composition
val addOne: Int => Int = _ + 1
val multiplyByTwo: Int => Int = _ * 2

val addThenMultiply = addOne andThen multiplyByTwo
val multiplyThenAdd = addOne compose multiplyByTwo

println(addThenMultiply(5))   // (5 + 1) * 2 = 12
println(multiplyThenAdd(5))   // (5 * 2) + 1 = 11

// Collection operations with higher-order functions
val numbers = List(1, 2, 3, 4, 5)

val squared = numbers.map(x => x * x)
val evens = numbers.filter(_ % 2 == 0)
val sum = numbers.reduce(_ + _)
val product = numbers.fold(1)(_ * _)

// FlatMap for nested transformations
val nested = List(List(1, 2), List(3, 4), List(5))
val flattened = nested.flatMap(identity)

val pairs = numbers.flatMap(x => numbers.map(y => (x, y)))

// Custom higher-order functions
def retry[T](times: Int)(operation: => T): Option[T] = {
  @scala.annotation.tailrec
  def attempt(remaining: Int): Option[T] = {
    if (remaining <= 0) None
    else {
      try {
        Some(operation)
      } catch {
        case _: Exception => attempt(remaining - 1)
      }
    }
  }
  attempt(times)
}

def withLogging[T](name: String)(operation: => T): T = {
  println(s"Starting $name")
  val result = operation
  println(s"Finished $name")
  result
}

// Measuring execution time
def timed[T](operation: => T): (T, Long) = {
  val start = System.nanoTime()
  val result = operation
  val elapsed = System.nanoTime() - start
  (result, elapsed / 1000000)  // Convert to milliseconds
}

val (result, time) = timed {
  (1 to 1000000).sum
}
println(s"Result: $result, Time: ${time}ms")
```

Higher-order functions enable powerful abstraction, allowing you to capture
common patterns and eliminate code duplication.

## Pattern Matching

Pattern matching provides elegant syntax for conditional logic and data
extraction, far more powerful than traditional switch statements.

```scala
// Basic pattern matching
def describe(x: Any): String = x match {
  case 0 => "zero"
  case 1 => "one"
  case i: Int => s"integer: $i"
  case s: String => s"string: $s"
  case _ => "unknown"
}

// Matching with guards
def classify(x: Int): String = x match {
  case n if n < 0 => "negative"
  case 0 => "zero"
  case n if n > 0 && n < 10 => "small positive"
  case n if n >= 10 => "large positive"
}

// Destructuring case classes
case class Point(x: Int, y: Int)

def locationDescription(point: Point): String = point match {
  case Point(0, 0) => "origin"
  case Point(0, y) => s"on Y-axis at $y"
  case Point(x, 0) => s"on X-axis at $x"
  case Point(x, y) if x == y => s"on diagonal at ($x, $y)"
  case Point(x, y) => s"at ($x, $y)"
}

// List pattern matching
def sumList(list: List[Int]): Int = list match {
  case Nil => 0
  case head :: tail => head + sumList(tail)
}

def describeList[T](list: List[T]): String = list match {
  case Nil => "empty"
  case _ :: Nil => "single element"
  case _ :: _ :: Nil => "two elements"
  case _ :: _ :: _ :: _ => "three or more elements"
}

// Variable binding in patterns
def processMessage(msg: Any): String = msg match {
  case s: String if s.length > 10 => s"Long string: ${s.take(10)}..."
  case s @ String => s"String: $s"
  case n @ (_: Int | _: Double) => s"Number: $n"
  case _ => "Unknown type"
}

// Option pattern matching
def getUserName(userId: Int): Option[String] = {
  if (userId > 0) Some(s"User$userId") else None
}

def displayUserName(userId: Int): String = getUserName(userId) match {
  case Some(name) => s"Welcome, $name"
  case None => "User not found"
}

// Either pattern matching
def divide(a: Int, b: Int): Either[String, Double] =
  if (b == 0) Left("Division by zero")
  else Right(a.toDouble / b)

def describeDivision(result: Either[String, Double]): String = result match {
  case Left(error) => s"Error: $error"
  case Right(value) => s"Result: $value"
}

// Tuple pattern matching
def

Related in General