0% found this document useful (0 votes)
42 views87 pages

Unit1 - Haskell

The document outlines the topics to be covered in the Principles of Programming Languages course across 3 units. Unit 1 will cover programming paradigms and functional programming with Haskell. Unit 2 will discuss concurrency in Java. Unit 3 provides an overview of functional programming with Scala.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views87 pages

Unit1 - Haskell

The document outlines the topics to be covered in the Principles of Programming Languages course across 3 units. Unit 1 will cover programming paradigms and functional programming with Haskell. Unit 2 will discuss concurrency in Java. Unit 3 provides an overview of functional programming with Scala.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 87

19CSE313

PRINCIPLES OF PROGRAMMING
LANGUAGES
D R . E . SO PHIYA
ASSISTAN T PR OF E SSOR/ CSE
AM R ITA VISHWA VID YAPEE THAM
Unit 1
Programming Paradigms – Overview of different programming paradigms.
Functional Programming with Haskell –functions and types, functional
composition, numbers, lists, tuples, type classes, pattern matching, higher order
functions: currying, lambdas, maps and filters, folds, IO monad
Unit 2
Concurrency in Java - Issues with concurrency: safety, liveness, fairness,
Threads, locks and synchronization, Thread pools, Futures and callables, fork-join
parallel framework
Unit 3
Functional Programming overview with Scala – Basic types and operations,
classes and objects, functional objects, functions and closure, composition and
inheritance

III CSE B
2
Unit 1
Programming Paradigms
Programming paradigms are different ways or styles in which a given
program or programming language can be organized.
Each paradigm consists of certain structures, features, and opinions about
how common programming problems should be tackled.
You can't "build" anything with a paradigm. They're more like a set of ideals
and guidelines.
Programming languages aren't always tied to a specific paradigm.
Enforced by compiler during compilation

III CSE B
3
Overview of different
programming paradigms
Imperative: Programming with an explicit sequence of commands.
Control flow in imperative programming is explicit.
◦ defines the solution to a problem as a series of steps
◦ individual statements, instructions, or function calls.
◦ how to achieve the goal

Declarative: The programmer doesn't give instructions about how the


computer should execute the task, but rather on what result is needed.
◦ Logic of the program

III CSE B
4
Finding the sum of all the numbers in
our list.
IMPERATIVE DECLARATIVE

total = 0 mylist = [1,2,3,4,5]


myList = [1,2,3,4,5] total = sum(mylist)
for x in myList: print(total)
total += x
print(total)

III CSE B
5
Imperative Programming Declarative Programming

Computation describe the step-by-step instructions for set the conditions that trigger the program
how an executed program achieves the execution to produce the desired results.
desired results.

Readability and add more features and code to your less complex and requires less code, making it
complexity program, it can become longer and more easier to read.
complex, making it increasingly confusing
and time-consuming to read.

Customization have complete control to edit and can easily Customizing the source code is more difficult
adapt the structure of your program to your because of complicated syntax and the
needs. paradigm’s dependence on implementing a
pre-configured algorithm.

Optimization Adding extensions and making upgrades are You can easily optimize code because an
supported, but doing so is significantly more algorithm controls the implementation.
challenging than with declarative Furthermore, you can add extensions and
programming, making it harder to optimize. make upgrades.

Structure The code structure can be long and complex. The code structure is concise and precise, and
The code itself specifies how it should run it lacks detail. Not only does this paradigm
and in what order. Due to the increased vastly limit the complexity of your code, but
complexity, the code can sometimes be the code is more efficient.
confusing because it may perform more than
one task.

III CSE A 6
III CSE B 7
Procedural Programming
Follows imperative programming with procedural calls referred as function,
method or subroutines.
Each function performs specific operation.
These calls direct the system to perform the required tasks.
Each procedure or so-called function can have multiple commands to be
executed.
The function, once defined, can be called as many times as needed.
Example: program that gives us factorial of a number
Languages: C, Java, Python, Pascal, PHP

III CSE B
8
It's simple. The program is very unique
An easier way to keep track of program is static and not expected to
program flow. change much over time
It has the ability to be strongly None or only a few features are
modular or structured. expected to be added to the project
over time
Needs less memory: It's efficient and
effective.

III CSE B 9
Object Oriented Programming
In OOP programming, all the
program components are represented
as objects. hide
Redefine by many forms
group
An object binds the data and the
associated methods together as
single unit.
The programmer can control the data
access permissions by defining the
share
access specifier.
Languages: C++, Java, Python, VB,
Ruby
Attributes and behavior

III CSE B 10
Example: find the sum of first ten natural numbers
public class Main
{
public static void main(String[] args) {
Addition obj = new Addition();
obj.num = 10;
int answer = obj.addValues();
System.out.println("The sum is = "+answer); //prints-> The sum is 55
}
}
class Addition {
int sum =0;
int num =0;
int addValues(){
for(int i=1; i<=num;i++){
sum += i;
}
return sum;
}}

III CSE B 11
Reuse of code through Inheritance. a lot of code that could be shared
and reused
Flexibility through Polymorphism.
project is anticipated to change often
High security with the use of and be added to over time
Encapsulation and Abstraction
mechanisms.

III CSE B 12
Parallel processing
processing of program instructions by dividing them among multiple
processors.
A parallel processing system allows many processors to run a program in less
time by dividing them up.
Languages: C, C++
Speeds up performance.
divide and conquer method
a system that has more than one CPU or multi-core processors
real-world data that needs more dynamic simulation and modeling

III CSE B
13
Declarative:
Logic programming
Based on formal logic
isn't made up of instructions - rather it's made up of facts and rules
Execution of the program is very much like proof of mathematical statement
Languages: Prolog, ALF, Alice, Ciao
Example:
man(Socrates). // fact: object `Socrates' is a man
mortal(X) :- man(X). // rule: "X is mortal if X is a man;''
?- mortal(Socrates). //query: "Is Socrates mortal?''

III CSE B
14
Easy to implement the code. Projects like theorem proving, expert
systems, term rewriting, type
Debugging is easy. systems and automated planning
it's structured using true/false
statements, we can develop the
programs quickly using logic
programming.

III CSE B 15
Functional programming
Execution of series of mathematical Example:
functions.
function isPrime(number){
All code is within a function.
for(let i=2;
All variables are scoped to the function. i<=Math.floor(Math.sqrt(number)); i++){
Functions do not modify any values outside if(number % i == 0 ){
the scope of that function.
return false;
Languages: Haskell, Scala, Clojure, Racket,
JavaScript, Erlang, Lisp }
}
return true;
}
isPrime(15);

III CSE B 16
Functions can be coded quickly and Working with mathematical
easily. computations.
General-purpose functions can be Applications aimed at concurrency or
reusable which leads to rapid parallelism.
software development.
Unit testing is easier.
Debugging is easier.

III CSE B 17
Database processing
A database is an organized collection Example:
of structured information, or data
CREATE DATABASE personalDetails;
controlled by a database
management system (DBMS) CREATE TABLE Persons (

Data can then be easily accessed, PersonID int,


managed, modified, updated, LastName varchar(255),
controlled and organized.
FirstName varchar(255),
Language: Structured Query
Language (SQL) Address varchar(255),
City varchar(255)
);

III CSE B 18
Massive amount of data is handled Accessing, modifying, updating data
on the database.
Easy to validate and ensure the
consistency of data Communicating with servers.
Easy to update data

III CSE B 19
Functional Programming with
Haskell
Programs are functions
Functions transform input values into output values
lambda calculus
Functional Programming is a set of function definitions (Declarative)
Computation is a process of applying rules
Haskell – writing provably correct code
Rapid prototyping – Specification to implementation

III CSE B 20
Haskell is lazy.
◦ won't execute functions and calculate things until it's really forced to show you a
result

Haskell is statically typed


◦ When you compile your program, the compiler knows which piece of code is a
number, which is a string and so on.
◦ Haskell has type inference.
◦ don't have to explicitly label every piece of code with a type because the type
system can intelligently figure out a lot about it.
◦ say a = 5 + 4, you don't have to tell Haskell that a is a number

III CSE B
21
Installation
• https://www.haskell.org/downloads/
• ghc's interactive mode and call some function to get a very basic feel for haskell.
• Open your terminal and type in ghci.

• Prelude is a standard module of GHCi, that provides very useful functions.


• Prelude is the core library loaded by default in every Haskell program

III CSE B
22
GHC stands for Glasgow Haskell Compiler.
GHC is completely written in Haskell.
GHC supports parallel and concurrent programming, profiling for time and
space.

ghc Compiler generates native code.


ghci It is an interactive interpreter
and debugger.

III CSE B
23
Simple arithmetic
Evaluate any kind of Haskell expressions in interactive mode.

Operator Performs
+ Addition
- Subtraction
* Multiplication
/ Division
mod Get the remainder
rem Get the remainder, Sign of the result is
same as sign of x.
^ Calculates power, a^x return a to the power
x.

III CSE B
24
C:\Users\Sophiya>ghci
GHCi, version 9.2.5: https://www.haskell.org/ghc/ :? for help
ghci> 10+5
15
ghci> 10-5
5
ghci> 10*5
50
ghci> 10/5 or div 10 5
2.0
ghci> mod 10 5
0
ghci> rem 10 5
0
ghci> mod 5 10
5
ghci> rem 5 10
5
ghci> 10 ^ 5
100000
Always surround negative numbers in parenthesis
ghci> 10/(-3)
-3.3333333333333335
III CSE B
25
let - key word is used to define variables, functions in Haskell interpreter.

ghci> let a=10


ghci> let b=5
ghci> a+b
15
ghci> a-b
5
ghci> a*b
50
ghci> a/b
2.0
ghci> mod a b
0
ghci> rem a b
0
ghci> a^b
100000

III CSE B 26
Boolean operators
ghci> True && True
True
ghci> True && False
False
ghci> True || True
True
ghci> False || True
True
ghci> False || False
False
ghci> True || (5>12)
True
ghci> not True
False
ghci> not False
True

III CSE B 27
Haskell Function
Function description has two parts: Following are the naming conventions
◦ Data type of inputs and outputs to a function in Haskell
◦ Rule for computing output from inputs a. Function name must start with a
Example: lower case letter.
Type definition:
function name :: Type ->Type
b. List of parameters to a function
also start with a lower case letter
add :: Int ->Int
Rule: c. Better to follow camel case
add x y = x+y convention, while defining function
name, parameter names.
Example:
cube x = x * x * x Ex:
sumOfNumbers arg1 arg2 = arg1 +
arg2

III CSE B
28
Haskell functions take more priority than anything else.
ghci> let square x=x*x
ghci> square 5*2
50

III CSE B 29
The succ function takes anything that has a defined successor and returns
that successor.
ghci> succ 5
6
ghci> succ(succ 5)
7
ghci> min 2 3
2
ghci> max 1 10
10

III CSE B
30
ghci> (1+) 2 // successor function (\y->1+y)
3
ghci> (1/) 2 // reciprocation function
0.5
ghci> (*2) 2 // doubling function
4
ghci> (/2) 4 // halving function
2.0

III CSE A
31
Example Function
1. calculate simple interest.
Let Principal = P, Rate = R% per annum (p.a.) and Time = T years. Then,
Simple Interest = (P x R x T)/100
Open any text editor and type rule, save it as interest.hs. Haskell files stored with .hs extension.
p = 10000
r= 2

t=2
interest = (p*t*r)/100
Go to the directory, where your interest.hs is located and type the command ghci.
‘:load’ command is used to load Haskell file. You can use :l in short cut to load Haskell files (:l hello.hs).
Observe above code snippet, when the file is loaded, Haskell changes the prompt from prelude to *Main. You can use the
variables defined in interest.hs in *Main prompt.
ghci> :load interest.hs

[1 of 2] Compiling Main ( interest.hs, interpreted )


Ok, one module loaded.
ghci> interest
400.0

III CSE B
32
2. Find maximum of three numbers: if-else, max

largest a b c = if(a>=b) then if (a>=c) then a


else c else if (b>=c) then b else c
ghci> largest 10 20 30
30

largest a b c = max(max a b) (max b c)


largest 10 20 30

3. Find Fibonacci series

III CSE B 33
Following are the basic numeric types supported by Haskell. All these numeric
types are instances of Num.

Type Description
Int It is bounded integer type, represent integer values

Integer It is unbounded integer type, represent arbitrarily large integer


values. Size is limited by the amount of memory available on your
machine.

Float Single precision floating point value. Used to represent real numbers
like 10.32, 9.86 etc., Usage of Float is discouraged, since Haskell
compilers are written Double data type efficient code.

Double Double precision floating point value. Used to represent real numbers
like 10.32, 9.86 etc.,

III CSE B 34
type
Haskell is statically typed language
For statically typed languages, type of the variable is known at compile time.
Haskell Infer the types
If you don't specify type to a variable (or) any function, then Haskell automatically deduce the types.
ghci> let a =1
ghci> let b="xxx"

ghci> let c= False


ghci> :t a
a :: Num a => a
ghci> :t b

b :: String
ghci> :t c
c :: Bool
ghci> :t 5.4
5.4 :: Fractional a => a

ghci> :t 'x'
'x' :: Char

III CSE B 35
functions has types as well
ghci> :t (&&)
(&&) :: Bool -> Bool -> Bool
ghci> add x y =x+y
ghci> sub x y =x-y
ghci> :t add
add :: Num a => a -> a -> a
ghci> :t sub
sub :: Num a => a -> a -> a

III CSE B
36
Function composition
A function output can be passed as input to other function. Combining functions
by passing output of one function as input to other function is called composition
of functions.
composition is denoted by f{g(x)} where g() is a function and its output in
used as an input of another function, that is, f().
For example,

Let g(x) = 2x, f(x) = x + 1

then

f(g(x)) = f(2x) = 2x + 1

g(f(x)) = g(x+1) = 2 (x+1) = 2x + 2


ghci> let g x = 2*x
ghci> let f x =x+1
ghci> f(g 10)
21
ghci> g(f 10)
22
III CSE B 37
Lists []
To describe a collection of values Prelude> countries
Sequence of values of unique type. ["India","Australia","China"]
To define a list: keyword ‘let’ Prelude> odd
Syntax: let listName = [elem1, [1,3,5,7,9]
elem2, …. elemN]
Prelude> vowels
Example:
"aeiou“
Prelude> let countries = ["India",
"Australia", "China"] Prelude> let primes =[2,3,5,7,11]
Prelude> let vowels =['a', 'e', Prelude> primes
'i','o','u'] [2,3,5,7,11]
Prelude> let odd = [1,3,5,7,9]

III CSE B 38
List Functions
List in Haskell cannot be of mixed types
Example: [1,2, True] or [1, ‘a’, False]
List can be specified with its Type [T]
Example: [1,2,3,4]:: [Int]
[True, false]::[Bool]
[] empty list
List can be nested.
[[3,2]] :: [[Int]]

III CSE B 39
Prepend elements to a list:
ghci> 5:[]
using ‘:’ cons operator you can prepend
and element to a list. [5]
It adds a single element to ghci> 4:[5]
the beginning of a list (and returns a
new list). [4,5]

(:) :: element -> list -> consed-list ghci> 3:[4,5]

(:) :: a -> [a] -> [a] [3,4,5]

Prelude> 1:[2,3,4,5] ghci> 2:[3,4,5]

[1,2,3,4,5] [2,3,4,5]

: is right associative. ghci> 1:[2,3,4,5]

1:(2:(3: (4: (5: [])))) == 1:2:3:4:[5] [1,2,3,4,5]


==1:2:3:4:5:[]

III CSE B
40
Combine two lists
By using ++ operator, you can append one list to other. //known number of lists
(++) :: list1 -> list2 -> joined-list
(++) :: [a] -> [a] -> [a]
Prelude> let even =[2,4,6,8]
Prelude> let evenodd = even ++ odd //[1,2,3] ++ [4]
Prelude> evenodd
[2,4,6,8,1,3,5,7,9]

ghci> let oddeven =odd ++ even


ghci> oddeven
[1,3,5,7,9,2,4,6,8]

ghci> [True, False] ++ [False, False]


[True,False,False,False]

concat :: list-of-lists -> joined-list //unknown number of lists


concat :: Foldable t => t [a] -> [a]
ghci> concat [[1, 2, 3, 4, 5], [10, 20, 30, 40], [100, 200, 300]]
[1,2,3,4,5,10,20,30,40,100,200,300]

III CSE A 41
Access elements of a list
By using !! double-bang operator, you can access the elements of a list.
Elements indexed from 0.
!! 0 returns first element in the list
!! 1 returns second element in the list.
Prelude> odd_numbers
[1,3,5,7,9]
Prelude>
Prelude> odd_numbers !! 0
1
Prelude> odd_numbers !! 1
3
Prelude> odd_numbers !! 2
5

III CSE B
42
Decomposing lists
X:XS
last: Return last element of a list
head: Get first element of the list
last takes a list and return the last element
head takes a list and return first element of the list. of list.
//last :: [a] -> a
Head (X:XS) -> X //head :: [a] -> a

Prelude> primes Prelude> last primes


11
[2,3,5,7,11]
Prelude> head primes
2

tail: Return tail of list


tail takes a list and return a list by removing first
element from it.
tail (X:XS) -> Xs //tail :: [a] -> [a]
Prelude> tail primes

[3,5,7,11]

III CSE B 43
init: Return a list by excluding last element //init :: [a] -> [a]
init takes a list and return new list by excluding the last element.
Prelude> init primes
[2,3,5,7]

length: Get length of the list // length :: Foldable t => t a -> Int
length takes a list and return number of elements in the list.
Prelude> length primes
5

null: Check for list emptiness // null :: Foldable t => t a -> Bool
null takes a list and return True if list is empty, else False.
Prelude> null primes
False

reverse: Reverse a list // reverse :: [a] -> [a]


reverse takes a list and return new list that contains all the elements in reverse order.
Prelude> reverse primes
[11,7,5,3,2]
III CSE B 44
take: Get n elements from list //take :: Int -> [a] -> [a]
take takes a number n and a list, return first n elements from list.
Prelude> take 3 primes
[2,3,5]

drop: Drop elements from beginning of a list //drop :: Int -> [a] -> [a]
drop takes a number n and a list, return a new list by dropping first n elements.
Prelude> drop 2 primes
[5,7,11]

maximum: Get maximum element from a list // maximum takes a list and return
maximum element in the list.
Prelude> maximum primes
11

minimum: Get minimum element from a list


minimum takes a list and return minimum element in the list.
Prelude> minimum primes
2

III CSE B 45
sum: Get sum of elements in the list
sum takes a list of numbers and return sum of elements in the list.
Prelude> sum primes
28

product: get product of elements in the list


product takes a list and return product of all numbers in the list.
Prelude> product primes
2310

elem: Search for existence of an element


elem takes an element and list, return True if the element is in list, else
False.
Prelude> 2 `elem` primes // elem 2 [1,3,5,7,11]
True

ghci> notElem 1 [1,2,3,4,5]


False
ghci> 14 `notElem` [1..10]
True
III CSE B 46
Define range of elements
using .. (range) operator
Prelude>[1..5] return all the elements from 1 to 5.
[1,2,3,4,5]

using ranges you can specify a step.


Prelude> [2, 4 .. 10]
[2,4,6,8,10] return all the even numbers from 2 to 10

cannot specify more than the first two elements and the upper bound:
ghci> [1,3,5..10]
<interactive>:38:7: error: parse error on input `..‘

To generate a range in descending order, always specify the negative step:


ghci> [10..1]
[]
ghci> [10,8..1] list can be bound to a variable or
[10,8,6,4,2] passed as a function argument:
ghci> take 5 [1..]
Infinite lists [1,2,3,4,5]
[1..] generates infinite list like [1, 2, 3, ……..]

III CSE B 47
Be careful when using ranges with floating-point values, because it accepts spill-
overs up to half-delta, to fend off rounding issues:
ghci> [1.0,1.5..2.4]
[1.0,1.5,2.0,2.5]

ghci> [1.0,1.1..1.2]
[1.0,1.1,1.2000000000000002]

Step difference
[1,3..8] = [1,3,5,7]

[2,5..19]=[2,5,8,11,14,17]

[8,7..5]=[8,7,6,5]

[12,8..-9]=[12,8,4,0,-4,-8]

Prelude> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz“

Prelude> ['A', 'C'..'Z']


"ACEGIKMOQSUWY“
III CSE A 48
List comprehensions
Used to generate a specific set out of a generic set.
let outputList = [ <outputFunction> | <inputList>, <predicate> ] //[ x | x <- someList ]

generates a set of 10 numbers


ghci> [x|x<-[1..10]]
[1,2,3,4,5,6,7,8,9,10]
The expression x <-[1..10] is called a generator, as it states how to generate values for x.

Add some conditions (predicates) to comprehensions.


Predicates go after the binding parts and are separated from them by a comma.

returns the numbers in the same set that are equal or larger than 10
ghci> [x|x<-[1..10],x*2>=10]
[5,6,7,8,9,10]

ghci> [x|x<-[1..10],x*2<=10]
[1,2,3,4,5]

III CSE B 49
Comprehensions can have multiple generators, separated by commas.
cross product of two lists.
ghci> [(x,y)|x<-[1,2,3],y<-[1,2,3]]
[(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]

Dependant Generators
Later generators can depend on the variables that are introduced by
earlier generators.
ghci> [(x,y) | x <-[1..3], y <-[x..3]]
[(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)]

ghci> take 10 [(i,j) | i<-[1,2],j<-[1..]]


[(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10)]

Functions can be directly applied to x as well:


[ f x | x <- someList ]

[x*x | x <- [1..5]]


[1,4,9,16,25]

III CSE B 50
[x*x | x <- [1..5], isPrime x]
[4,9,25]

Guards List comprehensions can use guards to restrict the values


produced by earlier generators.
[x | x <-[1..10], even x]
[2,4,6,8,10]

[x | x <- [1..4], x <- [x*x+1], even x]


[2,10]

list of all the positive divisors (factors) of 15


ghci> [x|x<-[1..15], 15 `mod` x == 0]
[1,3,5,15]

map (1+) [1,2,3]


[2,3,4]

III CSE A 51
Zipping and Unzipping Lists
zip takes two lists and returns a list of corresponding pairs
zip :: [a] -> [b] -> [(a, b)]
zip (a:as) (b:bs) = (a,b) : zip as bs
ghci> zip [1,2,3][4,5,6]
[(1,4),(2,5),(3,6)]

Zipping two lists with a function:


zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (+) [1,3,5] [2,4,6]
[3,7,11]

unzip function, which takes a list of tuples and returns two lists, one with all the first
components and other one with the seconds
unzip :: [(a, b)] -> ([a], [b])
ghci> unzip [(1,2),(2,3),(3,4)]
([1,2,3],[2,3,4])
List Transformations
Use Library:
ghci> import Data.List

III CSE A 52
Transpose: takes a list of lists, which we can think of as a "matrix". Then it transposes the
matrix so that the rows are now the columns.
transpose :: [[a]] -> [[a]]
transpose [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

transpose [[1],[4,5],[7,8,9]]
[[1,4,7],[5,8],[9]]

transpose ["ABCD","abcd"]
["Aa","Bb","Cc","Dd"]

Intersperse: inserts separator between the elements of its list argument


intersperse :: a -> [a] -> [a]

intersperse 0 [1,2,3,4]
[1,0,2,0,3,0,4]

intersperse '-' "Hello“


"H-e-l-l-o“
intersperse ',' "abcde"
"a,b,c,d,e"
III CSE A 53
intercalate function takes a list and a "list of lists“ as input. Insert list in-between list and
flattens the result.
intercalate :: [a] -> [[a]] -> [a]
ghci> intercalate ", " ["Haskel", "Scala"]
"Haskel, Scala"

subsequences function returns the list of all subsequences of the argument.


subsequences :: [a] -> [[a]]
subsequences "abc"
["","a","b","ab","c","ac","bc","abc"]

take 8 $ subsequences ['a'..]


["","a","b","ab","c","ac","bc","abc"]

permutations function returns the list of all permutations of the argument.


permutations :: [a] -> [[a]]
permutations "abc"
["abc","bac","cba","bca","cab","acb"]

III CSE A 54
Strings are lists of characters internally

ghci> let x = ['a','m','r','i','t','a'] ghci> length "Amrita chennai!"


ghci> x 15
"amrita" ghci> head "Amrita chennai!"
ghci> :t x 'A'
x :: [Char] ghci> tail "Amrita chennai!"
ghci> let y="amrita" "mrita chennai!"
ghci> y ghci> take 6 "Amrita chennai!"
"amrita" "Amrita"
ghci> :t y ghci> take 7 "Amrita chennai!"
y :: String "Amrita "
ghci> x==y ghci> take 8 "Amrita chennai!"
True "Amrita c"

III CSE B 55
repeat: Produce infinite list
repeat takes an element and produces an infinite list of just that element.

Prelude> take 10 (repeat 1)


[1,1,1,1,1,1,1,1,1,1]

Prelude> take 10 (repeat "Hello")


["Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello","Hello"]

take 10 (cycle "abc")


"abcabcabca"
replicate: Replicate elements
replicate takes a number n, and an element
return a list that contains n copies of the element.

Prelude> replicate 5 100


[100,100,100,100,100]

Prelude> replicate 5 "Haskell“


["Haskell","Haskell","Haskell","Haskell","Haskell"]

Prelude> replicate 5 [1,2,3,4,5]


[[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
III CSE B 56
ghci> zip "abc" [1,2,3,4]
[('a',1),('b',2),('c',3)]

ghci> [ x | x <- "The quick brown fox jumps over the lazy dog.", x `elem` "aeiouy" ]
"euioouoeeayo"

III CSE A 57
Tuples
Supports multiple types of data together.
to define a tuple: use parentheses () with elements delimited by commas
Example:
Student Information: Name, Reg.no, Branch, etc.
ghci> let stud =("Hari",1001,"CSE")
ghci> stud
("Hari",1001,"CSE")
List of Marks for a course
ghci> let students=[("xxx", 97), ("xyy", 91)]
ghci> students
[("xxx",97),("xyy",91)]
Tuple types:
(1, True) :: (Int, Bool)
([1,2],3) :: ( [Int], Int)

III CSE B
58
ghci> students !! 0
("xxx",97)
ghci> students !! 1
("xyy",91)
Nested tuples
Just like lists, a tuple can has other tuple in it.
ghci> ((1,1),(2,2),(3,3))
((1,1),(2,2),(3,3))

ghci> (('a','b','c','d'))
('a','b','c','d')

Retrieving values from a tuple


fst : Get the first element in a tuple
fst takes a tuple with 2 elements and return first element.
ghci> fst (2,"hello")
2
snd : get second element in a tuple
snd takes a tuple with 2 elements and return second element.
ghci> snd (2,"hello")
"hello"

III CSE B 59
zip: Map two lists as list of tuples
zip takes two lists, it creates a list of tuples by joining the matching elements into pairs.
ghci> let list1=[1,2,3,4,5]
ghci> let list2=[5,4,3,2,1]
ghci> zip list1 list2
[(1,5),(2,4),(3,3),(4,2),(5,1)]

ghci> zip [1 .. 5] ["one", "two", "three", "four", "five"]


[(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five")]

III CSE B 60
types
Type can be considered as a value
Int type includes 1,2,..
Bool type includes True/False
But how do we make our own?
▪use the data keyword to define a type.
Syntax: data Type = Constructor1 | Constructor2
constructors - specify the different values that this type can have.
Example:
To create a Bool type
data Bool = False | True
Both the type name and the value constructors have to be capital cased.

III CSE B
61
Algebraic data types
Sum Types:
▪Represent a value that can be one of several possible choices.
data Bool = False | True type constructor - name of our
Data Cards = Hearts | Diamonds | Clubs | Spades type
data constructor - used to
Product Types: construct new instances of the
▪combine multiple values into a single value. type
▪Syntax: data Typeconstructor = dataconstructor Types wrapped
▪ values are stored as fields within a data constructor.
data Shape = Circle Float Float Float
first two fields are the coordinates of its center, the third one its radius
data Person = Person String Int
a person with a name and an age

III CSE A
62
Sum and Product Types:
Combine sum and product types to create more complex data structures.
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
Circle and Rectangle are different constructors representing different shapes
Rectangle: the first two are the coordinates to its upper left corner and the
second two are coordinates to its lower right one.
data Employee = Manager String Int | Developer String Int
Manager and Developer are constructors each containing a name and an
employee ID.

III CSE A
63
Maybe:
A function might not be able to return a value for a certain input.
ghci> :info Maybe
type Maybe :: * -> *
data Maybe a = Nothing | Just a
If the function succeeds, we wrap the result in Just. Otherwise, we return
Nothing, which symbolizes something similar to null.

III CSE A
64
ghci> :cd F:\Amrita\Class Works\Dec 2023\PPL\class practice
ghci> :load types.hs
[1 of 2] Compiling Main ( types.hs, interpreted )
head' :: [a] -> Maybe a Ok, one module loaded.

head' [] = Nothing ghci> head' [1..5]


head' (x : _) = Just x Just 1
ghci> head' []
tail' :: [a] -> Maybe [a] Nothing
tail' [] = Nothing ghci> tail'[1..5]
tail' (_ : xs) = Just xs Just [2,3,4,5]
ghci> tail'[]
Nothing
last' :: [a] -> Maybe a ghci> last'[1..5]
last' = head' . reverse Just 5
ghci> last'[]
init' :: [a] -> Maybe [a] Nothing
init' [] = Nothing ghci> init' [1..5]
init' [x] = Just [] Just [1,2,3,4]
init' xs = Just (reverse(tail(reverse xs))) ghci> init' [1]
Just []
ghci> init' []
Nothing

III CSE A
65
Shape
Examples:
Write a function that takes a shape and returns its surface.
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
surface :: Shape -> Float
surface (Circle _ _ r) = pi * r ^ 2
surface (Rectangle x1 y1 x2 y2) = abs (x2-x1) * abs (y2-y1)
ghci> surface $ Circle 10 20 10
314.15927
ghci> c= Circle 10 20 10
ghci> surface c
314.15927

III CSE A 66
ghci> surface $ Rectangle 1 1 4 5
12.0
ghci> r= Rectangle 1 1 4 5
ghci> surface r
12.0
ghci> Circle 10 20 10
<interactive>:43:1: error:
* No instance for (Show Shape) arising from a use of `print'
* In a stmt of an interactive GHCi command: print it
Deriving Instances: can automatically derive instances for your types
data Type = Constructor1 | Constructor2 deriving (Eq, Show)
if we add deriving (Show) at the end of a data declaration, Haskell automagically makes that
type part of the Show typeclass
data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show)
ghci> Circle 10 20 10
Circle 10.0 20.0 10.0
III CSE A
67
Value constructors are functions, so we can map them and partially apply them and everything
If we want a list of concentric circles with different radii, we can do using map.
ghci> let circles = map (Circle 10 20) [3,4,5,6]
[Circle 10.0 20.0 3.0,Circle 10.0 20.0 4.0,Circle 10.0 20.0 5.0,Circle 10.0 20.0 6.0]
ghci> let surfacecircles = map surface circles
ghci> surfacecircles
[28.274334,50.265484,78.53982,113.097336]
Similarly, If we want a list of rectangles with different right corners:
ghci> let rect =map (\ (x,y) -> Rectangle 1 1 x y) [(3,4),(4,5)]
ghci> rect
[Rectangle 1.0 1.0 3.0 4.0,Rectangle 1.0 1.0 4.0 5.0]
ghci> let surfacerect = map surface rect
ghci> surfacerect
[6.0,12.0]

III CSE A
68
Let’s make an intermediate data type that defines a point in two-dimensional
space.
So now the Circle has two fields, one is of type Point and the other of type Float. Same
goes for the rectangle.

data Point = Point Float Float deriving (Show)


data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
surface :: Shape -> Float
surface (Circle _ r) = pi * r ^ 2
surface (Rectangle (Point x1 y1) (Point x2 y2)) = lx * ly
where
lx = abs (x2 - x1)
ly = abs (y2 - y1)

ghci> surface (Circle (Point 10 20) 5)


78.53982

ghci> surface (Rectangle (Point 1 1) (Point 3 4))


6.0
III CSE A 69
Record
we want to store about a person is: first name, last name, age, height and
phone number.
data Person = Person String String Int Float String deriving (Show)
firstName :: Person -> String
firstName (Person firstname _ _ _ _ ) = firstname

lastName :: Person -> String


lastName (Person _ lastname _ _ _ ) = lastname

age :: Person -> Int


age (Person _ _ age _ _ ) = age

height :: Person -> Float


height (Person _ _ _ height _ ) = height

phoneNumber :: Person -> String


phoneNumber (Person _ _ _ _ number) = number

III CSE A 70
ghci> let x = Person "John" "dalton" 65 184.0 "98756xxxxx"
ghci> x
Person "John" "dalton" 65 184.0 "98756xxxxx“

data Person = Person { firstName :: String


, lastName :: String
, age :: Int
, height :: Float
, phoneNumber :: String }
deriving (Show)

ghci> let y =Person "John" "dalton" 65 184.0 "98756xxxxx"


ghci> y
Person {firstName = "John", lastName = "dalton", age = 65, height = 184.0,
phoneNumber = "98756xxxxx"}

The main benefit of this is that it creates functions that lookup fields in the data type. By
using record syntax to create this data type, Haskell automatically made these functions:
firstName, lastName, age, height and phoneNumber.

III CSE A 71
ghci> 2+3
5
ghci> 2.0+3.0
5.0
+ operator works for a bunch of different underlying data types.
ghci> 2==2
True
ghci> 2==5
False
ghci> [2,5] == [2,5]
True
== operator can compare all sorts of values
operator “overloading” to support ad–hoc polymorphism.

III CSE A
72
Operator function for +
(+) :: Integer -> Integer -> Integer
(+) :: a -> a -> a
Qualified Types
ghci> :t (+)
(+) :: Num a => a -> a -> a
+ takes in two a values and returns an a value for any type a that is a Num or is an
instance of Num.
The name Num can be thought of as a predicate over types.
Some types satisfy the Num predicate.
Examples:
int, Integer, Double etc, and any values of those types can be passed to +

III CSE A
73
Other types do not satisfy the predicate.
Examples: Char, String, functions etc, and so values of those types cannot be
passed to +.
ghci> 'a' + 'c'
<interactive>:19:5: error:
* No instance for (Num Char) arising from a use of `+'

III CSE A 74
Type Classes
A typeclass is a collection of operations (functions) that must exist for the
underlying type.
Example:
Num Typeclass includes int, Integer, Float, Double..
A type has an instance of a typeclass if it implements the methods of that
typeclass.
A generic interface that contain common operations applicable to number of
types.

III CSE A
75
Type Class
A type class is a set of functions,
along with their type signature. By
using the keyword ‘class’, you can Example:
define a type class. To know about Num class
Syntax ghci> :info Num
type Num :: * -> Constraint
class TypeClassName a where class Num a where
function1 :: type1 (+) :: a -> a -> a
(-) :: a -> a -> a
function2 :: type2
(*) :: a -> a -> a
.... negate :: a -> a
.... abs :: a -> a
signum :: a -> a
functionN :: typeN fromInteger :: Integer -> a

III CSE B 76
Num ghci> :t (*)
(*) :: Num a => a -> a -> a
Num is a numeric typeclass. ghci> 5* (6 :: Integer)
30
Its members have the property of ghci> :type it
being able to act like numbers. it :: Integer
ghci> :t 20 ghci> (5::Int) * (6:: Int)
30
20 :: Num a => a ghci> (5::Int) * (6:: Integer)
<interactive>:30:13: error:
ghci> 20 :: Int
* Couldn't match expected type `Int' with
20 actual type `Integer‘
ghci> (5::Int) + (6:: Int)
ghci> 20:: Integer 11
20
ghci> (5::Int) + (6.0:: Float)
ghci> 20 :: Float <interactive>:36:13: error:
* Couldn't match expected type `Int' with
20.0 actual type `
ghci> 20 :: Double
ghci> (5::Int) + (6:: Integer)
20.0 <interactive>:37:13: error:

III CSE A 77
ghci> 5+2
7 Standard addition, generally understood as
ghci> 5-3 associative and commutative
2
ghci> 5*3 a + (b + c) ≡ (a + b) + c
15 a+b≡b+a
ghci> negate 5
-5 Multiplication, an associative operation that's
ghci> abs (-5) distributive over addition
5
ghci> abs (5) a * (b * c) ≡ (a * b) * c
5 a * (b + c) ≡ a * b + a * c
ghci> 5+(3+2)
10
ghci> signum 5
1
ghci> signum 0
0
ghci> signum 5 * abs 5
5
III CSE A 78
EQ type class is an interface which provides the functionality to test the equality of an
expression. Any Type class that wants to check the equality of an expression should be a
part of this EQ Type Class.
ghci> :info Eq ghci> 2 == 2
type Eq :: * -> Constraint True
class Eq a where ghci> 2 /= 2
False
(==) :: a -> a -> Bool
ghci> 'a' == 'a'
(/=) :: a -> a -> Bool True
instance Eq Bool -- Defined in `GHC.Classes' ghci> "amrita" == "amrita"
instance Eq Char -- Defined in `GHC.Classes' True
instance Eq Double -- Defined in `GHC.Classes' ghci> "Amrita" == "AMrita"
instance Eq Float -- Defined in `GHC.Classes' False
instance Eq Int -- Defined in `GHC.Classes' ghci> 3.14 == 3.14
instance Eq Ordering -- Defined in `GHC.Classes' True
instance Eq a => Eq (Solo a) -- Defined in `GHC.Classes' ghci> 5+(3+2) == (5+3)+2
instance Eq Word -- Defined in `GHC.Classes' True
instance Eq a => Eq [a] -- Defined in `GHC.Classes' ghci> 5*(3+5) == (5*3) + (5*5)
instance Eq a => Eq (Maybe a) -- Defined in `GHC.Maybe' True
instance (Eq a, Eq b) => Eq (Either a b) ghci> 5*(3*3) == (5*3)*3
True
III CSE B
79
Ord is for types which gives us the functionality of ordering.
ghci> :info Ord
▪ Ord covers all the standard comparing
type Ord :: * -> Constraint
class Eq a => Ord a where functions such as >, <, >= and <=.
compare :: a -> a -> Ordering
(<) :: a -> a -> Bool ▪ The compare function takes
(<=) :: a -> a -> Bool
two Ord members of the same type and
(>) :: a -> a -> Bool
(>=) :: a -> a -> Bool returns an ordering.
max :: a -> a -> a
min :: a -> a -> a ▪ Ordering is a type that can
instance Ord Bool -- Defined in `GHC.Classes'
instance Ord Char -- Defined in `GHC.Classes' be GT, LT or EQ
instance Ord Double -- Defined in `GHC.Classes'
instance Ord Float -- Defined in `GHC.Classes'
instance Ord Int -- Defined in `GHC.Classes'
instance Ord Ordering -- Defined in `GHC.Classes' data Ordering = LT | EQ | GT
instance Ord a => Ord (Solo a) -- Defined in `GHC.Classes'
instance Ord Word -- Defined in `GHC.Classes' compare :: Ord a => a -> a -> Ordering
instance Ord a => Ord [a] -- Defined in `GHC.Classes'
instance Ord a => Ord (Maybe a) -- Defined in
`GHC.Maybe'
instance (Ord a, Ord b) => Ord (Either a b)
-- Defined in `Data.Either'

III CSE B
80
ghci> 5>=7
ghci> "ABCDEF" `compare` "ABCD" False
GT
ghci> 12 `compare` 5 ghci> 7<=9
GT True
ghci> 5 `compare` 12
LT ghci> 3.9 > 9.0
ghci> 5 `compare` 5 False
EQ
ghci> "ABCD" `compare` "AMRITA" ghci> 'k' < 'z'
LT True
ghci> min 5 3
3 ghci> [1,2,3,4] <= [1,2,3,4]
ghci> max 10 12 True
12
ghci> 4<5 ghci> Just 5 <= Just 4
True False
ghci> 5> 3
True ghci> Nothing < Just 100
True
ghci> Nothing `compare` Nothing
EQ
III CSE A 81
Show has a functionality to print its argument as a String. Whatever may be its argument, it
always prints the result as a String.
ghci> :info show ghci> show (5==5)
type Show :: * -> Constraint "True“
class Show a where
... ghci> show (12 `compare` 5)
show :: a -> String "GT"
...
ghci> 5*3
ghci> show 310 15
"310"
ghci> show 10.56 ghci> show (5*3)
"10.56" "15“
ghci> show True
"True" ghci> show [x*2|x<-[1..10],even x]
ghci> show [1,2,3] "[4,8,12,16,20]“
"[1,2,3]"
ghci> show ['a'] ghci> show (3,'a')
"\"a\"" "(3,'a')“
ghci> show ['h','e','l','l','o']
"\"hello\"“ ghci> map show [x*2|x<-[1..10],even x]
["4","8","12","16","20"]
III CSE B
82
Read is sort of the opposite typeclass of Show. The read function takes a string and returns a
type which is a member of Read.

ghci> :info read ghci> read "[1,2,3,4]" ++ [5]


read :: Read a => String -> a [1,2,3,4,5]

ghci> read "True" || True ghci> read "5"


True *** Exception: Prelude.read: no parse
ghci> read "5" :: Int
ghci> read True || True 5
<interactive>:118:6: error: ghci> read "5" :: Float
* Couldn't match type `Bool' with `[Char]‘ 5.0
ghci> (read "5" :: Float) * 4
ghci> read "5.5" + 3.6 20.0
9.1 ghci> read "[1,2,3,4]" :: [Int]
[1,2,3,4]
ghci> read "5.5" - 3.6 ghci> read "(3, 'a')" :: (Int, Char)
1.9 (3,'a')

III CSE A 83
Enum members are sequentially ordered types — they can be enumerated.
▪Can use its types in list ranges.
▪Have defined successors and predecesors.
▪Types in this class: (), Bool, Char, Ordering, Int, Integer, Float and Double.
ghci> :info Enum
type Enum :: * -> Constraint
class Enum a where
succ :: a -> a
pred :: a -> a
toEnum :: Int -> a
fromEnum :: a -> Int
enumFrom :: a -> [a]
enumFromThen :: a -> a -> [a]
enumFromTo :: a -> a -> [a]
enumFromThenTo :: a -> a -> a -> [a]
III CSE B
84
ghci> [1..5] ghci> mylist = enumFromThen 4 6
[1,2,3,4,5] ghci> take 10 mylist
ghci> ['a'..'k'] [4,6,8,10,12,14,16,18,20,22]
"abcdefghijk“
ghci> [LT .. GT] ghci> mylist1 = enumFromThen 6 2
[LT,EQ,GT] ghci> take 8 mylist1
ghci> succ 'A' [6,2,-2,-6,-10,-14,-18,-22]
'B'
ghci> succ 6 ghci> enumFromTo 6 10
7 [6,7,8,9,10]
ghci> pred 10
9 ghci> enumFromTo 10 6
ghci> pred 'z' []
'y‘
ghci> enumFromThenTo 6 8 20
ghci> list = enumFrom 1 [6,8,10,12,14,16,18,20]
ghci> take 5 list
[1,2,3,4,5] ghci> enumFromThenTo 6 5 1
[6,5,4,3,2,1]

III CSE A 85
class BasicEq a where
ghci> isEqual 3 3
isEqual :: a -> a -> Bool
instance BasicEq Bool where
<interactive>:66:1: error:
isEqual True True = True * Ambiguous type variable `a0' arising from a
isEqual False False = True use of `isEqual'
prevents the constraint `(BasicEq a0)' from
isEqual _ _ = False being solved.

Probable fix: use a type annotation to


specify what `a0' should be.
ghci> :load isequal.hs
These potential instance exist:
ghci> isEqual True False instance BasicEq Bool -- Defined at
isequal.hs:3:10
False
* In the expression: isEqual 3 3
ghci> isEqual False False
In an equation for `it': it = isEqual 3 3
True

III CSE B
87
USING TYPECLASSES
1.Define
An Insert function
Insertion sort
2. showList for Characters

III CSE B 88

You might also like