Higher-Order Functions & Currying
Explore advanced functional concepts like higher-order functions and currying to create flexible and reusable code.
Higher-Order Functions & Currying is a free Scala for Backend Engineering & Functional Programming lesson on CoddyKit — lesson 2 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Scala for Backend Engineering & Functional Programming learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Unlocking Higher-Order Functions
Welcome to Lesson 2! In functional programming, functions are powerful. They aren't just for calculating values; they can also be treated like any other data.
This means functions can be passed as arguments to other functions, or even returned as results from them. When a function does this, it's called a Higher-Order Function (HOF).
- HOFs take one or more functions as arguments.
- HOFs return a function as a result.
- Or both!
HOF in Action: `map`
One of the most common HOFs in Scala is map. It transforms each element of a collection by applying a given function to it, returning a new collection.
Try running this simple example:
object Main {
def main(args: Array[String]): Unit = {
val numbers = List(1, 2, 3)
val doubledNumbers = numbers.map(x => x * 2)
println(s"Original: $numbers")
println(s"Doubled: $doubledNumbers")
}
}HOF in Action: `filter`
Another useful HOF is filter. It selects elements from a collection that satisfy a given condition (a function that returns a boolean), creating a new collection.
Here's how you can use filter to find even numbers:
object Main {
def main(args: Array[String]): Unit = {
val allNumbers = List(1, 2, 3, 4, 5, 6)
val evenNumbers = allNumbers.filter(x => x % 2 == 0)
println(s"All: $allNumbers")
println(s"Even: $evenNumbers")
}
}Defining Your Own HOF
You're not limited to built-in HOFs! You can define your own functions that accept other functions as parameters. The syntax for a function type is (InputType => ReturnType).
This example defines a function applyOperation that takes an Int and another function op (which takes an Int and returns an Int).
object Main {
// A HOF that applies an operation to a number
def applyOperation(x: Int, op: Int => Int): Int = {
op(x)
}
def main(args: Array[String]): Unit = {
val result = applyOperation(10, _ * 3) // Pass an anonymous function
println(s"Result of 10 * 3: $result")
val anotherResult = applyOperation(7, _ + 5)
println(s"Result of 7 + 5: $anotherResult")
}
}Anonymous Functions & Shorthand
When passing functions to HOFs, you often use anonymous functions (also called lambdas). Scala provides concise ways to write them.
x => x * 2: Full anonymous function._ * 2: Shorthand for a single-parameter anonymous function.
Both are common and make your code shorter and more readable.
object Main {
def main(args: Array[String]): Unit = {
val numbers = List(10, 20, 30)
// Using full anonymous function syntax
val dividedByTwo = numbers.map(x => x / 2)
println(s"Divided by two: $dividedByTwo")
// Using shorthand `_` syntax
val plusOne = numbers.map(_ + 1)
println(s"Plus one: $plusOne")
}
}Introducing Currying
Currying is a technique that transforms a function taking multiple arguments into a sequence of functions, each taking a single argument.
It's named after logician Haskell Curry. In Scala, functions with multiple parameter lists are automatically curried.
Instead of f(arg1, arg2), you write f(arg1)(arg2).
Currying Example: Multi-Parameter Lists
Let's see currying in action. Notice how add takes its arguments in two separate parameter lists.
This allows you to partially apply the function, creating new functions by fixing some arguments.
object Main {
// A curried function with two parameter lists
def add(a: Int)(b: Int): Int = {
a + b
}
def main(args: Array[String]): Unit = {
// Call the function normally
println(s"5 + 3 = ${add(5)(3)}")
// Partially apply the first argument
val addFive = add(5)_ // `_` tells Scala to treat it as a partially applied function
println(s"5 + 10 = ${addFive(10)}")
println(s"5 + 20 = ${addFive(20)}")
}
}Benefits of Currying
Why use currying? It offers several advantages in functional programming:
- Partial Application: Create specialized versions of a function by fixing some arguments. This improves code reuse.
- Function Composition: Curried functions are often easier to compose with other functions.
- Type Inference: Can sometimes help Scala's type inference, especially when working with complex generic types.
Currying for Custom Loggers
Imagine you want to create different logging functions for different levels (e.g., INFO, ERROR) but use the same core logic. Currying is perfect for this!
You can define a general log function and then partially apply it to create specific loggers.
object Main {
def log(level: String)(message: String): Unit = {
println(s"[$level] $message")
}
def main(args: Array[String]): Unit = {
// Create specialized loggers using partial application
val infoLogger = log("INFO")_
val errorLogger = log("ERROR")_
infoLogger("User logged in successfully.")
errorLogger("Failed to connect to database!")
}
}Quick Check: HOFs and Currying
Consider the following Scala code snippet:
def calculate(x: Int)(y: Int, op: (Int, Int) => Int): Int = {
op(x, y)
}
val add = (a: Int, b: Int) => a + b
val multiply = (a: Int, b: Int) => a * b
val result1 = calculate(10)(5, add)
val result2 = calculate(2)(3, multiply)What are the values of result1 and result2?
Recap: HOFs & Currying
Great job! You've explored two powerful concepts in functional programming:
- Higher-Order Functions (HOFs): Functions that can take other functions as arguments or return them as results. They enable flexible and reusable code, like
mapandfilter. - Currying: A technique to transform a function with multiple arguments into a sequence of functions, each taking a single argument. It's excellent for partial application and creating specialized functions.
These concepts are fundamental to writing expressive and modular Scala code!
Frequently asked questions
Is the “Higher-Order Functions & Currying” lesson free?
Yes — the full text of “Higher-Order Functions & Currying” is free to read here on the web, and the Scala for Backend Engineering & Functional Programming course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Scala for Backend Engineering & Functional Programming course, upgrade to CoddyKit PRO.
What will I learn in “Higher-Order Functions & Currying”?
Explore advanced functional concepts like higher-order functions and currying to create flexible and reusable code. You practise Scala for Backend Engineering & Functional Programming with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Scala for Backend Engineering & Functional Programming?
No prior experience is required. Scala for Backend Engineering & Functional Programming on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 3, so you can start here or from the beginning and move at your own pace.
How long does the “Higher-Order Functions & Currying” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Scala for Backend Engineering & Functional Programming lesson?
Yes. Every Scala for Backend Engineering & Functional Programming lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Functions as First-Class Values
- Higher-Order Functions & Currying
- Immutability and Side Effects