FP UNIT1 Notes
FP UNIT1 Notes
UNIT - 1
Syllabus:
Introducing Functional Programming: Defining Functional Programming, Considering Other
Programming Paradigms, Using Functional Programming to Perform Tasks, Discovering
Languages That Support Functional Programming.
Getting and Using Haskell: Working with Haskell, Obtaining and Installing Haskell,
Compiling a Haskell Application, Using Haskell Libraries, Getting Help with the Haskell
Language.
Defining the Functional Difference: Comparing Declarations to Procedures, Understanding
How Data Works, Seeing a Function in Haskell, Seeing a Function in Python
_____________________________________________________________________________
The main difference between the functional programming paradigm and other paradigms is that
functional programs use math functions rather than statements to express ideas. This difference
means that rather than write a precise set of steps to solve a problem, use math functions, and
don’t worry about how the language performs the task. In some respects, this makes languages
that support the functional programming paradigm similar to applications such as MATLAB.
Using this approach to defining a problem relies on the declarative programming style, which is
used with other paradigms and languages, such as Structured Query Language (SQL) for
database management. In contrast to other paradigms, the functional programming paradigm
doesn’t maintain state. The use of state enables to track values between function calls. Other
paradigms use state to produce variant results based on environment, such as determining the
number of existing objects and doing something different when the number of objects is zero. As
a result, calling a functional program function always produces the same result given a particular
set of inputs, thereby making functional programs more predictable than those that support state.
Because functional programs don’t maintain state, the data they work with is also immutable,
which means that one cannot change it. To change a variable’s value, one must create a new
variable. Again, this makes functional programs more predictable than other approaches and
could make functional programs easier to run on multiple processors.
Object-oriented programming (OOP) simply modularizes and hides the steps, but the underlying
paradigm is the same. Even with modularization, OOP often doesn’t allow rearrangement of the
object code in unanticipated ways because of the underlying interdependencies of the code.
Functional programming gets rid of the interdependencies by replacing procedures with pure
functions, which requires the use of immutable state. Consequently, the assembly line no longer
exists; an application can manipulate data using the same methodologies used in pure math. The
seeming restriction of immutable state provides the means to allow anyone who understands the
math of a situation to also create an application to perform the math.
Using pure functions creates a flexible environment in which code order depends on the
underlying math. That math models a real-world environment, and as our understanding of that
environment changes and evolves, the math model and functional code can change with it —
without the usual problems of brittleness that cause imperative code to fail.
Modifying functional code is faster and less error prone because the person implementing the
change must understand only the math and doesn’t need to know how the underlying code
works. In addition, learning how to create functional code can be faster as long as the person
understands the math model and its relationship to the real world.
Functional programming also embraces a number of unique coding approaches, such as the
capability to pass a function to another function as input. This capability enables to change
application behavior in a predictable manner that isn’t possible using other programming
paradigms.
______________________________________________________________________________
Procedural
Procedural programming implements imperative programming, but adds functionality such as
code blocks and procedures for breaking up the code. The compiler or interpreter still ends up
producing machine code that runs step by step, but the use of procedures makes it easier for a
developer to follow the code and understand how it works. Many procedural languages provide a
disassembly mode in which you can see the correspondence between the higher-level language
and the underlying assembler. Examples of languages that implement the procedural paradigm
are C and Pascal.
Early languages, such as Basic, used the imperative model because developers creating the
languages worked closely with the computer hardware. However, Basic users often faced a
problem called spaghetti code, which made large applications appear to be one monolithic piece.
Consequently, languages that follow the procedural paradigm are a step up from languages that
follow the imperative paradigm alone.
Object-oriented
The procedural paradigm does make reading code easier. However, the relationship between the
code and the underlying hardware still makes it hard to relate what the code is doing to the real
world. The object-oriented paradigm uses the concept of objects to hide the code, but more
important, to make modeling the real world easier. A developer creates code objects that mimic
the real-world objects they emulate. These objects include properties, methods, and events to
allow the object to behave in a particular manner. Examples of languages that implement the
object-oriented paradigm are C++ and Java.
Languages that implement the object-oriented paradigms also implement both the procedural and
imperative paradigms. The fact that objects hide the use of these other paradigms doesn’t mean
that a developer hasn’t written code to create the object using these older paradigms.
Consequently, the object-oriented paradigm still relies on code that modifies application state,
but could also allow for modifying variable data.
Declarative
Functional programming actually implements the declarative programming paradigm, but the
two paradigms are separate. Other paradigms, such as logic programming, implemented by the
Prolog language, also support the declarative programming paradigm.
The short view of declarative programming is that it does the following:
»»Describes what the code should do, rather than how to do it.
»»Defines functions that are referentially transparent (without side effects).
»»Provides a clear correspondence to mathematical logic.
_____________________________________________________________________________
»»Pure functions: A pure function has no side effects. When working with a pure function,
one can
• Remove the function if no other functions rely on its output
• Obtain the same results every time a function is called with a given set of inputs
• Reverse the order of calls to different functions without any change to application functionality
• Process the function calls in parallel without any consequence
• Evaluate the function calls in any order, assuming that the entire language doesn’t allow side
effects
»»Recursion: Functional language implementations rely on recursion to implement looping.
In general, recursion works differently in functional languages because no change in application
state occurs.
»»Referential transparency: The value of a variable never changes in a functional
language implementation because functional languages lack an assignment operator.
Some languages use strict (eager) evaluation, while other languages use non-strict (lazy)
evaluation.
Under strict evaluation, the language fully checks the function before evaluating it. Even when
a term within the function isn’t used, a failing term will cause the function as a whole to fail.
However, under non-strict evaluation, the function fails only if the failing term is used to create
an output. The Miranda, Clean, and Haskell languages all implement non-strict evaluation.
______________________________________________________________________________
For example, allowing any modification of application state would instantly disqualify a
language from consideration. One of the more common and less understood reasons for
disqualifying a language as being a pure implementation of the functional programming
paradigm is the lack of pure-function support. A pure function defines a specific relationship
between inputs and outputs that has no side effects. Every call to a pure function with specific
inputs always garners precisely the same output, making pure functions extremely reliable.
______________________________________________________________________________
»»Linux Mint
»»Redhat
»»Fedora
»»Gentoo
Download the tarball and follow these instructions to install it:
1. Type tar xf haskell-platform-8.2.2-unknown-posix--full-i386.tar.gz and press Enter.
The system extracts the required files.
2. Type sudo ./install-haskell-platform.sh and press Enter.
1. Locate the downloaded copy of Haskell Platform 8.2.2 Full 64bit-signed.pkg on your
system.
2. Double-click the installation file.
Haskell Platform 8.2.2 64-bit Setup dialog box will appear.
3. Click Next.
The wizard displays a licensing agreement.
4. Click I Agree if you agree to the licensing agreement.
The setup wizard asks where you want to install your copy of Haskell.
5. Click Next.
A dialog box asking which features to install will appear
6. Click Next.
A new dialog box will appear that asks where to install the Haskell Stack. Use the default
installation location to ensure that setup works correctly.
7. Click Next.
The setup wizard asks which features to install. Install all of them.
8. Click Install.
You see the Haskell Stack Setup wizard complete.
9. Click Close.
You see the Haskell Platform wizard progress indicator move. At some point, the installation
completes.
10. Click Next.
You see a completion dialog box.
11. Click Finish.
Haskell is now ready for use on your system.
The setup wizard asks you which Start menu folder to use, as shown in Figure 3-3.
7. Optionally type a new Start menu folder name and click Install.
A new dialog box appear that asks where to install the Haskell Stack.
Platform 8.2.2. No matter how the interpreter is opened , the version number of installation can
be seen, as shown in Figure 3-4.
The interpreter can provide a great deal of information about Haskell. The commands all start
with a colon, including the help commands. So to start the process, you type :? and press Enter.
Figure 3-5 shows typical results.
As look through the list all commands beginning with a colon, can be seen. For example, to exit
the Haskell interpreter, type :quit and press Enter. Type "Haskell is fun!" and press Enter. See
the string repeated onscreen, as shown in Figure 3-6. All Haskell has done is evaluate the string
which was provided. As a next step, try creating a variable by typing x = "Haskell is really
fun!" and press Enter. This time, Haskell doesn’t interpret the information but simply places the
string in x
To see the string, use the putStrLn function. Type putStrLn x and press Enter. Figure 3-7 shows
what is seen. At this point, it will be known that the Haskell installation works.
______________________________________________
Type the following code into the file and save it on disk:
To compile a Haskell application, there must be a main function, which consists of a single
statement, which in this case is putStrLn out. The variable out is defined as part of the where
clause as the concatenation of a string, "5! = ", and an integer, result, that is outputted using the
show function. The code must be indented, to compile correctly.
The code calculates the result by using the fac (factorial) function that appears below the main
function. The first line defines the stopping point. When the input is equal to 0, the function
outputs a value of 1. Otherwise, the second line is used to call fac recursively, with each
succeeding call reducing the value of n by 1 until n reaches 0. After the file is saved , open GHCi
or WinGHCi, to experiment with the application.
The following steps provide the means to load, test, and compile the application:
The output of the application is shown in Figure 3-9. When working with WinGHCi, we can also
use the Actions ➪ Run “main” command or we can click the red button with the right-pointing
arrow on the toolbar.
However, when creating a procedure, we can add conditions that rely on state to affect output.
For example, we might add a step to the procedure that checks the time of day. If it’s evening,
the recipient might return coffee instead of tea, knowing that the requestor always drinks coffee
in the evening based on the steps in the procedure. A procedure therefore offers flexibility in its
capability to interpret conditions based on state and provide an alternative output. Declarations
are quite strict with regard to input. The example declaration says that a cup of tea is needed, not
a pot or a mug of tea. The MakeMeTea procedure,however, can adapt to allow variable inputs,
which further changes its behavior.
One of the hardest issues in moving from imperative languages to functional languages is the
concept of declaration. For a given input, a functional language will produce the same output and
won’t modify or use application state in any way. A declaration always serves a specific purpose
and only that purpose.
The second hardest issue is the loss of control. The language decides how to perform tasks, not
the developer.
______________________________________________________________________________
\
Understanding How Data Works
Data is a representation of something — perhaps a value. However, it can just as easily represent
a real-world object. The data itself is always abstract, and existing computer technology
For example, in the following code, the output of the comparison between id(x) and oldID
will be false:
x=1
oldID = id(x)
x=x+1
id(x) == oldID
When working with other languages, we need to consider whether the data supported by that
language is actually immutable and what set of events occurs when code tries to modify that
data. In Haskell, modifications aren’t possible, and in Python, we can detect changes, but not all
languages support the functionality required to ensure that immutability is maintained.
isn’t returning a value. Side effects also occur in data. When we pass a variable to a function, the
expectation in functional programming is that the variable’s data will remain untouched —
immutable. A side effect occurs when the function modifies the variable data so that upon return
from the function call, the variable changes in some manner.
______________________________________________________________________________
Seeing a Function in Haskell
Haskell is all about functions, it supports a lot of function types. It does demonstrate two of the
more important function types (non-curried and curried).
Functions can act as the basis for other functions. Incrementing a number is really just a special
form of addition.
Consequently, you can create the inc function shown here:
inc (x) = add (x, 1)
As you can see, add is the basis for inc. Using inc is as simple as typing something like inc 5 and
pressing Enter. Note that the parentheses are optional, but you could also type inc (5) and press
Enter. Figure 4-2 shows the result.
We don’t actually see the true effect of currying, though, until you create the inc function. The
inc function really does look different, and the effects are even more significant when function
complexity increases:
inc = add 1
This form of the inc function is shorter and actually a bit easier to read. It works the same way as
the non-curried version. Simply type something like inc 5 and press Enter to see the result shown
in Figure 4-4.
Interestingly enough, we can convert between curried and non-curried versions of a function as
needed using the built-in curry and uncurry functions.
Try it with add by typing uadd = uncurry add and pressing Enter. To prove to ourself that uadd
is indeed the non-curried form of add, type uadd 1 2 and press Enter.
You see the error shown in Figure 4-5.
We can use curried functions in some places where non-curried functions won’t work. The map
function is one of these situations.
The following code adds a value of 1 to each of the members of the list:
map (add 1) [1, 2, 3]
The output is [2,3,4] as expected. Trying to perform the same task using uadd results in an error,
as shown in Figure 4-6.
______________________________________________
Seeing a Function in Python
Functions in Python look much like functions in other languages.
Creating and using a Python function
Python relies on the def keyword to define a function.
For example, to create a function that adds two numbers together, you can use the
following code:
def add(x, y):
return x + y
To use this function, we can type something like add(1, 2). Figure 4-7 shows the output of this
code when we run it in Notebook.
As with Haskell, we can use Python functions as the basis for defining other functions.
For example, here is the Python version of inc:
def inc(x):
return add(x, 1)
The inc function simply adds 1 to the value of any number. To use it, we might type something
like inc(5) and then run the code, as shown in Figure 4-8, using Notebook.
To avoid this problem, we must create a new variable within the function, change its value, and
then return the new variable, as shown in the following code:
def DoChange(aList):
newList = aList.copy()
newList.append(4)
return newList
aList = [1, 2, 3]
print(aList)
print(DoChange(aList))
print(aList)
Figure 4-9 shows the results. In the first case, we see the changed list, but the second case keeps
the list intact.