Scala Functional Patterns
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.
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
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.