NashTech Blog

Lenses, Prisms and Optics in Scala

Table of Contents
Choose services and resources for performance tuning

Introduction

In functional programming, optics are crucial for simplifying tasks and handling immutable data. As you know, Scala is a versatile language that offers helpful tools for working with optics. These tools enable developers to write concise, meaningful code for managing complex data transformations. In this blog, we’ll explore lenses, prisms, and optics in Scala, along with some straightforward examples of their usage.

Lenses, Prisms and Optics in Scala

Before we explore the specific examples, let’s briefly understand what lenses, prisms, and optics, so here we will start with lenses first –

Lenses

A lens is a functional abstraction that allows us to view and modify a specific part of an immutable data structure. It consists of two main operations: “get” to extract a value from the structure, and “set” to update the values. Lenses provide a clean and compatible way to work with nested data structures, such as case classes or collections.

Understanding Lens Operations:
  1. Get Operation: The “get” operation retrieves a value from the data structure. It takes the entire data structure as input and returns the focused part.
  2. Set Operation: The “set” operation updates a value in the data structure. It takes the entire data structure and a new value for the focused part as input and returns a new updated data structure.

Prisms

Prisms are like tools borrowed from optics, which is a part of math and computer science. They help us deal with different types of data in a certain way. In functional programming, prisms help us work with things like optional values or nested data structures, making sure everything fits together correctly and is easy to use.

Understanding Prisms Operations:

At its core, a prism consists of two main components: the Prisms itself and a pair of functions getOrModify and reverseGet.

  1. getOrModify: This function takes a value of the larger type and attempts to extract a value of the smaller type. If successful, it returns the extracted value; otherwise, it returns the original value unchanged.
  2. reverseGet: This function takes a value of the smaller type and embeds it back into the larger type.
Benefits of Using Prisms:

Prisms offer below advantages:

  1. Type Safety: Prisms provide a type-safe way to work with optional or nested data structures, reducing the risk of runtime errors.
  2. Composition: Prisms can be composed together to work with more complex data structures, enabling code reuse and modularity.
  3. Conciseness: By abstracting away common patterns, prisms lead to more concise and readable code, improving maintainability.

Optics

Optics is like a tool in math and computer science. It helps to change certain types of information in a computer without actually changing the main structure of that information. It uses things like lenses, prisms, and traversals to do this. With optics, we can easily look at and change parts of complicated data without messing up the whole thing.

The main idea of optics is to separate the way we look at and change data from how the data is stored. This makes it easier to write code that’s easy to use again and again, making software that’s easier to keep up to date.

Benefits of Using Optics:
  1. Composability: You can put optics together to handle complicated data setups. This makes it easier to reuse code and keep things organized.
  2. Type Safety: Optics let you view, change, and update data in a way that’s safe for the type of data you’re working with. This helps prevent errors that can happen while your program is running.
  3. Immutability: Optics keep data from being changed directly. Instead, they make new copies of the data with the changes you want. This helps ensure that the original data stays the same, which is important for maintaining consistency.

Now, let’s see how we can use these ideas in Scala.

We’ll use a library called Monocle. It’s well-liked in the Scala community and helps with things like lenses, prisms, and other similar concepts. To begin, we’ll include Monocle as a dependency for our Scala project.

libraryDependencies += "com.github.julien-truffaut" %% "monocle-core" % "3.1.0"

Once we have Monocle added to our project, we can start using lenses and prisms.

Example 1: Using Lenses

Suppose we have a case class representing a user:

case class User (id: Int, name: String, address: Address)
case class Address (city: String, pin: String)

We can define lenses for accessing and modifying nested fields:

import monocle.Lens

val addressLens: Lens[User, Address] = Lens[User, Address](_.address)(newAddress => _.copy(address = newAddress))

// Get the user's address
val user = User(1, "Utkarsh", Address("Punjab", "202334"))
val address = addressLens.get(user) // Output: Address(Punjab,202334)

// Modify the user's address
val updatedUser = addressLens.modify(_.copy(city = "Noida"))(user)
// Output: User(1,Utkarsh,Address(Noida,202334))

Example 2: Using Prisms

Let’s define a sealed trait representing different payment methods:

sealed trait PaymentMethod
case class SBICard(number: String, expiry: String) extends PaymentMethod
case class UPI(email: String) extends PaymentMethod

We can create prisms for each payment method to safely extract and modify values:

import monocle.Prism

val cardPrism: Prism[PaymentMethod, SBICard] = Prism[PaymentMethod, SBICard]{
  case cc: SBICard => Some(cc)
  case _ => None
}(identity)

// Extract card information safely
val paymentMethod: PaymentMethod = SBICard("0000 0000 0000 0000", "30/28")
val cardInfo = cardPrism.getOption(paymentMethod) // Output: Some(SBICard(0000 0000 0000 0000,30/28))

Conclusion

In this blog post, we looked at how we can use special tools called lenses, prisms, and optics in Scala using something called the Monocle library. These tools help us work with data in a way that doesn’t change it, and they let us do complicated changes in a simpler, more organized way. When we add these tools to our Scala code, it means we can write code that’s easier to keep up to date, shorter, and clearer.

Refrences :
https://scalac.io/blog/scala-optics-lenses-with-monocle/

Picture of utkarshup

utkarshup

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top