Software DevelopmentLearn How To Write Functions In Functional Programming Style In Scala

Learn How To Write Functions In Functional Programming Style In Scala

Write Functions
When you write programs in a functional style it is a requirement that you use pure functions. To begin understanding the concept of pure functions we first need to understand what referential transparency is. An expression satisfies referential transparency if its result can replace it and program behavior does not change in any way. This replacement does not depend on context so it must hold wherever substitution happens in the program.

To demonstrate this consider two immutable variables used in an expression as shown below
a + b
Let us create another expression as shown below
val c = a + b

Wherever we can use the expression a + b in our program we can instead use c and get the same results. This is an overly simplified example of how referential transparency is implemented. For a function to be deemed pure it needs to satisfy two properties. These are referential transparency and no side effects on its inputs. When working with pure functions it is important to keep the following points in mind.

  • The number of input parameters passed to a function is one or more
  • Results of a function only depend on passed parameters and defined expressions.
  • The function should not change any of the passed parameters
  • The function is not allowed to change the state of either its class or object
  • Pure functions are not allowed to engage in any I/O activities like doing disk reads, writes and interacting with user via input

Before we demonstrate how to convert impure functions to pure functions it is important to highlight some examples of each. Examples of pure functions are

  • Mathematical operations, although they may not seem so they are function calls. For example look at the addition example given previously. It operates on a and b and returns a result which only relies on a and b without changing them
  • Methods such as map and filter that operate on immutable collections

Examples of impure functions are

  • Methods that operate on date and time given an input will return a different value when called at different times. Such functions violate the property of referential transparency.
  • Functions that perform reads and writes on external data

From the previous discussion it is clear functional programming places restrictions on some aspects that would be required for a software program to work. It is unthinkable a program would work without processing user input or performing database reads and writes. The best approach to this dilemma is to create as much functional code then develop small code base to deal with operations that have side effects. This way you are able to get the best from each programming style.
When impure functions update their state it results in side effects which violate referential transparency. To overcome this violation we avoiding updating state by use of side effects and instead return new state together with the value we have generated. By doing this we leave the old state intact. Whenever you are faced with the problem of converting a problem into a pure function this is the approach to use.
In the next section we are going to look at how we can convert a java class written using object oriented design to a Scala functional program. Consider the java program below that is used to filter, sort and place names in a list.

public class User {
  private final int id;
  private final String firstName;
  private final String lastName;
  private final Boolean active;  
}
public static List<String> activeById(List<User> us) {
   List<User> users = new ArrayList<User>();
   for (User u: us) {
     if (u.getActive()) users.add(u);
   }
   Collections.sort(users, new Comparator<User>() {
      public int compare(User a, User b) {
        return a.getId() - b.getId();
      } 
   });
   
   List<String> finalUsers = new ArrayList<String>();
   for (User u: users) {
     finalUsers.add(u.getLastname());
   }
   return finalUsers;
}
List<User> inputUsers = new ArrayList<User>();
inputUsers.add(new User(30, "don", "Arachi", false));
inputUsers.add(new User(22, "james", "blaine", true));
inputUsers.add(new User(44, "aggrey", "kevin", true));
List<User> activeUsersById = activeById(inputUsers)

When we rewrite the above java program into a functional Scala program the result is shown below. In our Scala program we have used filter and map methods that we had earlier noted are examples of pure functions. In the Scala program there is no need to maintain state so the code becomes cleaner. Another benefit of not changing variables comes when writing high concurrency programs you are sure there will be no problems.

In a functional approach we split our tasks into many small methods. This is referred to as composition. In the simplified functional code we have relied on filter, sortBy and map methods

case class User(id: Int, firstname: String, lastname: String, active: Boolean)
def activeById(us: Seq[User]) = us.filter(_.active).sortBy(_.id).map(_.lastname)
val activeUsersById = activeById(Seq(
  User(30, "don", "arachi", false),
  User(22, "james", "blaine", true),
  User(44, "aggrey", "kevin", true)
))

In this tutorial pure functions were introduced and the properties that need to be satisfied for a function to be considered pure were discussed. We highlighted several points that a programmer needs to have in mind when using pure functions. An example of an OOP implementation was discussed and an equivalent FP approach was discussed.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Exclusive content

- Advertisement -

Latest article

21,501FansLike
4,106FollowersFollow
106,000SubscribersSubscribe

More article

- Advertisement -