Programming Paradigms: Declarative

Shivam
Analytics Vidhya
Published in
7 min readFeb 12, 2020
Photo by Markus Spiske on Unsplash

Hello there,

In the first blog post, we discussed the imperative and declarative paradigms. Also, in the second blog post, we covered the paradigms influenced by the imperative paradigm. In this blog post, We are going to cover the paradigms, which are the forms of the declarative paradigm. If you haven’t read my previous blogs on paradigms, then I would recommend you to read it before going further.
Following are the list of some paradigms which are influenced by the declarative paradigms:

  1. Functional Paradigm
  2. Logical Paradigm

Functional programming:

The principles of modularity and code reuse in functional programming are the same as in procedural programming since they both stem from structured programming. For example, Procedures resemble functions. Both allow the reuse of the same code in various parts of the programs.

The main difference between the styles is that functional programming languages remove the imperative elements of procedural programming. As we know, the assignment operator and global variable are two main aspects of the imperative programming. So the functional programming doesn’t recommend the use of an assignment operator and accessing the variables outside of function scope. Yeah, you read it right, Coding without assignment operator.

The benefit of this approach is, No assignment operator = No changing the value of variables = No side effect. But we know that when we do some calculations or apply some logic, we need variables to store those results, then how can we achieve this in the functional programming?. Well, instead of assigning values to variables, we pass those values as input arguments to the same or other functions.

And No side effect means the function doesn’t change the value of any variable, which is outside of its scope. This approach leaves the system in the same state as it was before calling the function.

In other words, the output of any function is dependent only on the inputs of the function, and it doesn’t matter how many times we call the function using the same input arguments every time function will return the same output. This is only possible when we don’t access/change the state of a variable, which is outside of the function’s scope.

Let’s take an example of a program that calculates the sum of first n numbers. In the below code snippet, function sum() is changing the value of the variable total, which is outside of its scope. Not only that, but the initial value is also making an effect on the final value of the variable total. Hence, the function sum doesn’t produce the same result all the time, even when we pass the same input to it.

Figure 1.1

After reading the above example you might be like, Dude, you said no assignment operator, right?. Yeah, but that was procedural programming style, and it is ok to use assignment operator in it. Here is the example in the functional style:

Using Functional Programming Style.

No assingment operator, no saving the state. No use of loops. Nice, isn’t it?

The features of functional languages are designed to support writing programs in terms of pure functions. In functional programming, we use function recursion instead of loops for traversing in the set of values. Most of the functional programming support features like higher-order functions, lambda functions, anonymous functions, closures, function recursion, etc. to give more power to function.

Features of Functional Programming:

Most of the functional programming languages support the following features:

Higher-order functions:

Higher-order functions are functions that can either take other functions as an argument or return a function as results.

First-class functions:

Functions are first-class citizens in functional programming that means there is no restriction on their use. And they can appear anywhere in the program just like other first-class entities such as numbers. For example, we can assign a function to a variable, pass it to other functions as arguments, and can use them as a return value of a function.

Recursion:

Iteration (looping) in functional languages is usually accomplished via recursion. Recursive functions invoke themselves, and it keeps repeating until it reaches the base case.

Lazy evaluation:

Lazy evaluation does not evaluate function arguments unless their values are required to evaluate the function call itself.

Referential transparency:

Functional programs are referentially transparent, which means any variable can be replaced with its actual value. This eliminates any chances of side effects because the value of a variable will never change once defined.

Assignment statements are never referentially transparent, and this is one of the reasons for not promoting assignment statements in functional programming. Consider the following example, here the initial value of a variable total is 0, but we can’t replace all occurrences of the variable total by its value i.e., 0, as it is getting assigned to new value every time we iterate. So, we can say the below program is not referentially transparent.

Now, consider the following example, we can replace all occurrences of n by its value, as it is not getting changed throughout the program. So, we can call below program as referential transparent.

Functional vs. Procedural Programming:

In Procedural Programming, the execution of the program is a sequence of imperative commands that may implicitly alter the shared state (the variable total in the above example(Figure 1.1) is shared).

In Functional programming, the execution of the program is the evaluation of complex expressions that only depend on each other in terms of input arguments and return values. For this reason, functional programs can have a free order of code execution. Also, there is no shared element/state between the functions, and it means they can be used independently without affecting each other. This approach is beneficial when it comes to concurrency and multi-threaded programming.

Logical programming:

In the Logical style of programming, first, we define some known facts and rules to make computers aware of the problem domain. Then, when we ask queries to a computer, it makes some logical deduction based on the initially given facts and rules, and returns a solution to our problem. The logical programming language includes Prolog, answer set programming (ASP), and Datalog.

The Logical Paradigm takes a declarative approach to problem-solving. In logical programming, we have various logical assertions, and their execution is performed using a model generator whose behavior is not controlled by the programmer.We can create logical assertions using rules which are written in the form of clauses, in the below Prolog example H is head, and the B is a body:

H :- B.

poet(X) :- human(x).

We read this as — X is a poet if x is a human.

Facts are rules that have no body and are written in the simplified form as:

H.

animal(cat)

We read this as — cat is a animal.

Here are the example rules which teaches a computer about what Sam likes to eat and what he doesn’t like to eat.

As a computer knows about Sam’s likes and dislikes, now we can ask questions like, whether Sam likes paneer_tikka or not?

?- likes(sam,paneer_tikka).

true.

We can also query for all dishes that sam likes using:

?- likes(sam,X).
X = paneer_tikka ;
X = roti ;
X = noodles ;
X = hakka_noodles ;
X = pizza ;
X = spaghetti ;

See, we just asked computer to give us the value of X, but we didn’t tell computer how to get the value X. This is declarative way of programming.

Thanks for reading this blog. I hope you enjoyed this series on the Programming Paradigms and learned something new. If you have any suggestions or questions, please add it in the comment below, Happy Learning 👏.

More From Me:

--

--

Shivam
Analytics Vidhya

Product Engineer @ Gojek. Likes to write on Productivity, Android App Development, Kotlin, Software Engineering, etc.