Tutorials

Scala | Lambdas and Higher Order Functions

Key Takeaways

  • Scala anonymous functions, or lambdas, create function values that you can store, pass as arguments, and return.
  • Int => Int describes a function that takes one integer and returns an integer.
  • A higher-order function accepts a function, returns a function, or does both.
  • Use named parameters while learning; shorten x => x + 5 to _ + 5 when the meaning stays clear.

Scala anonymous functions let you express behavior as a value. Higher-order functions accept or return those values, letting you separate processing logic from the code that invokes it.

The complete program below targets Scala 3 and runs as a source file. Run each smaller snippet independently in a Scala 3 REPL—the interactive prompt—or a worksheet.

What Is an Anonymous Function in Scala?

An anonymous function, also called a lambda, defines behavior without declaring a named method. For example, (x: Int) => x + 5 takes an integer and returns that integer plus five.

// Scala 3 REPL or worksheet
val addFive = (x: Int) => x + 5
addFive(10) // 15

The expression to the right of = is a function literal: source-code syntax that creates a function value. Here, addFive names the resulting value; assigning it to a variable doesn't turn the lambda into a method or restrict it to one use.

Scala's function variables documentation makes this distinction explicit. For the broader idea behind treating behavior as data, see what functional programming means.

Reading Scala Function Types

The type of addFive is Int => Int. Read the left side as the input type and the right side as the result type; in the lambda expression itself, the right side of => is the body to execute.

With an expected function type, Scala can infer the parameter type:

// Scala 3 REPL or worksheet
val explicit = (x: Int) => x + 5
val inferred: Int => Int = x => x + 5
val shorthand: Int => Int = _ + 5

All three values have type Int => Int. In the first declaration, the parameter annotation supplies the input type; in the other two, the annotation on the value supplies it. By contrast, val unknown = x => x + 5 lacks the information needed to infer x's type.

What Is a Higher-Order Function?

A higher-order function takes at least one function as an argument or returns a function as its result. Scala uses this term for both methods and function values with that behavior, as the official higher-order functions tutorial explains.

A Runnable processAndPrint Example

Save this complete Scala 3 program as LambdaDemo.scala:

def processAndPrint(value: Int, processor: Int => Int): Unit = {
  val newValue = processor(value)
  println(s"Processed value is: $newValue")
}

@main def lambdaDemo(): Unit = {
  val addFive: Int => Int = x => x + 5
  assert(addFive(10) == 15)

  processAndPrint(10, addFive)
  processAndPrint(10, _ * 2)
  processAndPrint(10, _ + 5)
}

With a modern Scala installation, run it using the scala command:

scala run LambdaDemo.scala

The program prints:

Processed value is: 15
Processed value is: 20
Processed value is: 15

The processor parameter expects an Int => Int function value. Calling processor(value) executes that function; processAndPrint then prints its result and returns Unit, rather than returning the processed integer.

A higher-order function isn't limited to one function parameter. You can accept multiple functions when the operation needs separate behaviors, such as a transformation and a validation rule.

Scala Anonymous Functions with map and filter

Collection operations are an everyday use of higher-order functions. On a list, map applies a function to each element and returns a list of results; filter keeps the elements for which its function returns true.

// Scala 3 REPL or worksheet
val numbers = List(1, 2, 3)

val shifted = numbers.map(x => x + 5)  // List(6, 7, 8)
val shorter = numbers.map(_ + 5)       // List(6, 7, 8)
val odd = numbers.filter(x => x % 2 != 0) // List(1, 3)

Here, map supplies the expected input type from the list's Int elements, so you don't need (x: Int). The function passed to filter has type Int => Boolean; a function returning a Boolean is called a predicate. Neither operation modifies numbers.

What Does Underscore Mean in a Scala Lambda?

In numbers.map(_ + 5), _ + 5 is placeholder syntax for x => x + 5. The placeholder stands for the function's incoming argument.

Within one placeholder expression, successive underscores represent successive parameters—not repeated uses of the same parameter:

// Scala 3 REPL or worksheet
val multiply: (Int, Int) => Int = _ * _
val square: Int => Int = x => x * x

multiply(3, 4) // 12
square(3)      // 9

Consequently, numbers.map(_ * _) isn't a shorthand for squaring each element: it describes a two-argument function where map needs a one-argument function. For repeated parameters, nested lambdas, or expressions you have to mentally expand, use names instead.

Methods vs. Function Values

A declaration using def defines a method. A function value is an object that you can store in a variable or pass around. Scala bridges the two through eta-expansion: the compiler creates a function value that calls the method.

// Scala 3 REPL or worksheet
def addFiveMethod(x: Int): Int = x + 5

val addFiveFunction: Int => Int = addFiveMethod
val results = List(1, 2, 3).map(addFiveMethod) // List(6, 7, 8)

In the map call, passing addFiveMethod works like passing x => addFiveMethod(x). Passing addFiveMethod(10) would instead pass the integer result, not a function.

The Scala guide to eta-expansion explains the conversion and the differences between Scala 2 and Scala 3. If variable declarations are unfamiliar, review Scala val vs var.

Returning a Function from a Function

Accepting a function is only half the definition of a higher-order function. You can also return one:

// Scala 3 REPL or worksheet
def makeAdder(amount: Int): Int => Int = x => x + amount

val addFive = makeAdder(5)
val addTen = makeAdder(10)

addFive(10) // 15
addTen(10)  // 20

Calling makeAdder(5) returns a function, not the result of an addition. The addition happens when you call that returned function.

The returned lambda retains access to amount from its surrounding scope. A function with captured surrounding values is called a closure. This lets you configure behavior once and reuse it later, as demonstrated in Scala's guide to methods that return functions.

Advantages of Using Anonymous Functions in Scala

Decoupling

In the runnable example, processAndPrint owns invocation and output formatting; its caller supplies the calculation. You can switch from adding five to multiplying by two without changing the printing code.

The calculation can also be checked separately: assert(addFive(10) == 15) tests the processor without inspecting console output. This separation is the useful part—not merely making the code shorter.

Convenience

For a small, one-off transformation, numbers.map(_ + 5) keeps the behavior next to its use without introducing a separate method. When the behavior grows or deserves a meaningful name, use a named method or function value instead.

A lambda isn't automatically pure: it can print or change state. Keep calculations separate from effects such as printing when you want them to be easier to reuse and test.

FAQ

How do you write an anonymous function in Scala?

Use a parameter list followed by => and a body, such as (x: Int) => x + 5. You can pass the expression directly to a higher-order function or store its function value in a val.

What is the difference between a Scala method and a function value?

A def declaration defines a method, while a function value is an object you can store and pass around. When a compatible function is expected, Scala can convert a method reference into a function value through eta-expansion.

What does _ mean in a Scala function expression?

In an expression such as _ + 5, the underscore is a placeholder for an anonymous function's parameter. Within one placeholder expression, successive underscores represent separate parameters, so _ * _ takes two arguments rather than squaring one.

Can Scala infer the parameter type of a lambda?

Yes, when the surrounding context supplies an expected type, as in val addFive: Int => Int = x => x + 5 or List(1, 2, 3).map(x => x + 5). Without that context, provide the parameter type explicitly, as in (x: Int) => x + 5.

What is a higher-order function in Scala?

A higher-order function accepts a function as an argument, returns a function, or does both. For example, List.map accepts a function, while makeAdder in this tutorial returns one.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. More about me