Purely functional Language
- Every Haskell funciton is pure
- Function will always yield the same output for the same argument
- No side effects
int n = 0;
int next_n() {
return n++;
}
Side effects
Function is said to have a side effect if it modifies some state or has an observable interaction
Referential transparency
# referentially opaque
g = 0
def f1( x ):
global g
g = g + 1
return g + x
# referentially transparent
def f2( x ):
return x + 1
python> f1( 4 ) == f1( 4 )
False
python> f2( 4 ) == f2( 4 )
True
Languages | Strong/Weak | Static/Dynamic |
---|---|---|
Java, C++, ML, Haskell | Strong | Static |
Python | Strong | Dynamic |
Javascript, PHP | Weak | Dynamic |
if ( true ) {
//do something
}
if ( 'a' ) {
//do something
}
if ( 42 ) {
//do something
}
if 'a'
then
-- do something
else
-- do other thing
-- Error: Couldn't match expected type `Bool' with actual type `Char'
Lazy evaluation (non-strict)
A code is executed only if its value is needed
Haskell can evaluate only a specific part of a very large data structure without loading the whole data into memory.
- lower memory footprint
- infinite data structure
Haskell is both compiled and interpreted
Most commonly used tools:
Glasgow Haskell Compiler
GHC (Haskell Compiler)
GHCi (Haskell Interpreter)
Int – bounded integer
Integer – unbounded integer
Float – real floating point with single precision
Double – real floating point with double precision
Bool – boolean type, True of False
Char – a character
Integer – unbounded integer
factorial :: Integer -> Integer
factorial n = product [1..n]
λ> factorial 40
815915283247897734345611269596115894272000000000
Int– bounded integer
factorial :: Int -> Int
factorial n = product [1..n]
λ> factorial 40
-70609262346240000
Float – real floating point with single precision
circumference :: Float -> Float
circumference r = 2 * pi * r
λ> circumference 5.0
31.415928
Double – real floating point with double precision
circumference :: Double -> Double
circumference r = 2 * pi * r
λ> circumference 5.0
31.41592653589793
Bool – boolean type. True of False
λ> True && False
False
λ> False || True
True
λ> not False
True
λ> True /= False
True
Boolean infix functions
Char – a character is denoted by a single quotes.
String is a list of characters.
λ> :t ‘x’
‘x’ :: Char
λ> :t “hello”
“hello” :: [Char]
Lists are a homogeneous data structure which store elements of the same type. Lists are denoted by a square brackets and its value are separate by commas.
λ> let x = [1,2,3,4]
λ> x
[1,2,3,4]
Functions that operate on lists
λ> [1,2,3,4] !! 1
2
List indexing
List concatenation
λ> let x = [1,2,3]
λ> let y = [4,5,6]
λ> x ++ y
[1,2,3,4,5,6]
Cons operator (prepend)
λ> ‘A’ : “ Dog”
“A Dog”
Functions that operate on lists
λ> head [1,2,3,4]
1
head
tail
λ> tail [1,2,3,4]
[2,3,4]
length
λ> length [1,2,3,4]
4
null
λ> null []
True
λ> null [1,2,3,4]
False
Ranges generate a lists that are arithmetic sequences of elements that can be enumerated.
λ> [1..10]
[1,2,3,4,5,6,7,8,9,10]
λ> [10,9..1]
[10,9,8,7,6,5,4,3,2,1]
Infinite list can be constructed by not specifying an upper limit.
λ> [1..]
[1,2,3,4..]
List comprehension is a syntactic construct for creating list based on existing lists. It follows the form of the mathematical set-builder notation (set comprehension)
This set comprehension can be written similarly as:
λ> [ 2*x | x <- [0..], x^2 > 3 ]
[4, 6, 8, 10, 12..]
python> [ 2*x for x in range( 10 ) if x**2 > 3 ]
[4, 6, 8, 10, 12, 14, 16, 18]
Tuples are like lists except that it does not have to be homogeneous.
Tuples are denoted with parentheses and their components are separated by commas.
λ> fst (1, 2.5)
1
Functions that operate on two tuples
fst – a function that take a two tuples and returns the first component
λ> let x = (1, ‘a’, 2.3)
λ> x
(1, ‘a’, 2.3)
λ> snd (1, 2.5)
2.5
snd – a function that take a two tuples and returns the second component
Haskell function can be difined in two parts:
1. Optional function declaration
2. Function implementation
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial(n-1)
Pattern matching
Function can be defined with separate function bodies for different type of arguments. The type of argument that matches the pattern will fall through the corresponding function body.
factorial :: Integer -> Integer
factorial n
| n == 0 = 1
| n > 0 = n * factorial (n-1)
Guards
Guards are similar to if else statement in imperative language. A guard determine a function body using a Boolean expression. If the expression evaluates to True, then the corresponding function body is used.
absolute x
| x < 0 = 0 – x
| otherwise = x
Guards
The keyword otherwise can be use to catches everything. otherwise is simply defines as True.
collatzSum :: Integer -> Integer
collatzSum n
| n < 0 = 0
| n == 1 = 1
| even n = n + collatzSum (n `div` 2)
| otherwise = n + collatzSum (3 * n + 1)
public int collatzSum(int n) {
if (n < 0)
return 0;
else if (n == 1)
return 1;
else if (n % 2 == 0)
return n + collatzSum(n / 2);
else
return n + collatzSum(3 * n + 1);
}
Haskell function is a first-class function. The language supports passing function as arguments to other functions, returning function as a values, assigning to a variable or storing in a data structures.
Haskell functions process one parameter at a time, using currying to support multiple arguments.
Calling a function with an incomplete argument resulting in a partially applied function.
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (h:t) = f h : map f t
λ> map (\x -> x + 1) [1,2,3]
[2,3,4]
public <T> T first(T x, T y) {
return x;
}
first :: a -> a -> a
first x y = x
(Parametric polymorphism)
λ> :t (==)
(==) :: (Eq a) => a -> a -> Bool
A class is an interface that defines a behavior of a type.
- Not object oriented class.
- Provide a way to control overloading (ad-hoc polymorphism).
If a type is a member of a class that means it supports and implements the behavior of the class describes.
[ x*2 | x <- [1..10], odd x ]
Monads is a function compositor.
Practical example: List Monad
List comprehension can be written using monads in different ways.
do
x <- [1..10]
if odd x
then [x*2]
else []
do syntax allows programmer to program in the imperative style.
[1..10] >>= (\x -> if odd x the [x*2] else [])
bind operator (>>=)