Download - Principles of functional progrmming in scala
Principles of Functional Progrmming in Scala
• Moor’s Law
• Clock frequency
has not raised.
• More Complex
programs.
• Growing in data
var x = 0
async{ x = x+1 }
async{ x = x*2 }
// the answer could be 0, 1 or 2
Non-determinism = parallel processing+ mutable values
Example
In science, a paradigm describes distinct concepts or
thought patterns in some scientific discipline.
Main programming paradigms:
imperative programming
functional programming
logic programming
Paradigm
modifying mutable variables,
using assignments
and control structures such as if-then-else, loops, break, continue, return.
Imparative paradigm
Immutable states
Functions without side-effects
Everything is function
Functions are expressions not statements
Fucntional Paradigm
once a variable is given a value it never changes.
no side effects are possible.
Functions are building blocks functions are free side-effect
function call does not affect other functions and it just computes its own output for a specific input
sin (pi) = 0
Functions are expressions not statements
Referential transparency
Neither theories nor functions have mutable values.
You can combine functions to make more complex functions
The result of a function or a theory does not change for different input.
(a+b)^2 = a^2 + b^2 + 2*a*b
This state doesn’t change for different inputs.
FP is inspired by mathematics
Pure(restricted) Functional languages ( no imperative structure) like: Pure Lisp, XSLT, XPath, XQuery, FP,Haskell (without I/O Monad or UnsafePerformIO)
Wider sense : Lisp, Scheme, Racket, ClojureSML, Ocaml, F# , Haskell (full language) , Scala , Smalltalk, Ruby
Functional Languages
Scala is a statically typed JVM language that has transparent interoperability with Java.
Both object oriented and functional language
What is scala?
Lightweight syntax
Combines functional and object-oriented approaches
Advanced type system: everything has a type
Strong type inference
Performance comparable to Java
Fully interoperable with Java
Why Scala?
Scala formclass person(val name: String , val age: Int) { ...}
Java formclass person{private String name;private int age;
Peron(String name, int age){
this.name = name;this.age = age;
}}
Example of Scala High-level syntax
val list = List(2,5,4)
val newList = (list map(x => x*x)) sortWith(_ > _)
//newList = list(4,16,25)
Java form ???
val people: Array[Person]
val (minors,adults) = people partition (_.age < 18)
Java form ???
continue
The idea underlying this model is that all evaluation does is reduce an expression to a value.
It can be applied to all expressions, as long as they have no side effects.
Lambda calculus
Subsitution Model
A non-primitive expression is evaluated as follows:
1. Take the leftmost operator
2. Evaluate its operands (left before right)
3. Apply the operator to the operands
(2 * pi) * radius
(2 * 3.14159) * radius
6.28318 * radius
6.28318 * 10
62.8318
Non-primitive expression
1. Evaluate all function arguments, from left to right
2. Replace the function application by the function’s right-hand side, and, at the same time
3. Replace the formal parameters of the function by the actual arguments
Parameterized functions substitution
1. sumOfSquares(3, 2+2)
2. sumOfSquares(3, 4)
3. square(3) + square(4)
4. 3 * 3 + square(4)
5. 9 + square(4)
6. 9 + 4 * 4
7. 9 + 16
8. 25
Example
What if right hand side does not terminate ?
two elements for storing expressions in Scala: def and val
def loop: Boolean = loop
def x = loop //it is ok
val x = loop // it will lead to an infinite loop.
As you see the difference between val and def becomes apparent when the right hand side does not terminate. Val is changed to its value when it is defined but the value of def is substituted where it is used.
Scala Substitution model
def:
1. can have parametersdef cube(x: Int): Int = x*x*x
2. Call-by-name
val:
1. The value of it is substituted as it is defined. In other words: call-by-value
val & def continue
sumOfSquares(x: Int , y: => Int)
sumOfSquares(3, 2+2)
square(3) + square(2+2)
3 * 3 + square(2+2)
9 + square(2+2)
9 + (2+2) * (2+2)
9 + 4 * (2+2)
9 + 4 * 4
25
Call-by-name function parameters
Functions are expressions so they can be:
Defined anywhere included in other functions
sent to other functions as parameters
Returned from other functions
def fact(x: Int) = if(x ==0) 1 else x*fact(x-1)
def cube(x: Int) = x*x
def processOnSums( f: Int => Int , a: Int , b: Int) = f(a) + f(b) processOnSums(cube, 2 , 3 ) // Output = 2*2 + 3*3
anonymous function: x=> x*x
processOnSums(fact , 2 , 3 ) // Output: 2*1 + 3*2*1
Higher-Order functions
def sum(f: Int => Int, a: Int, b: Int): Int = if (a > b) 0
else f(a) + sum(f, a + 1, b)
def sumInts(a: Int, b: Int) = sum(x=>x, a, b)
def sumCubes(a: Int, b: Int) = sum(x=> x*x, a, b)
def sumFactorials(a: Int, b: Int) = sum(x=>fact(x), a, b)
Can we make it even shorter???
Currying
def sum(f: Int => Int): (Int, Int) => Int = {def sumF(a: Int, b: Int): Int =if (a > b) 0else f(a) + sumF(a + 1, b)sumF}Sum returns another functionWe can define like this:def sumInts = sum(x => x)def sumCubes = sum(x => x * x * x)def sumFactorials = sum(fact)sumCubes(1, 10) + sumFactorials(10, 20)
Even shorter???
continue
Two kinds of instant field initialization:Class myClass(input1: Int, input2: Int)
{
Val a = input1
Vab b = input2
}
class myClass(val input1: Int, val input2: Int){…}
Classes
In order to create auxiliary constructors, define method this with required parameters.
Class myClass(input1: Int, input2: Int)
{
def this(input1: Int) = this (input1, 0)
}
Auxiliary Constructors
Inheritance rules so similar to java
Traits are alternative for interfaces
Why do we need a new structure ?
In java classes can have only one super class, but what if a class need to inherit from several supertypes ???
This is why scala introduces traits.
Inheritance
trait super
{
val a = 5
def b = a*2
def c(x: Int) = a*x
}
class sub extends Object with super{…}
Trait
Int scala.Int
Boolean scala.Boolean
Object java.lang.Object
require scala.Predef.require
assert scala.Predef.assert
Imports
The same as java. with new notationVal myList = new List(1,2,3)
The other form: Val myList = List(1,2,3)
What happened? Whre is new? We will see…
Object Definition
What is singleton object and why do we need it?
The reason we used singleton classes was to create just one object of a certain type.
Scala gives us a powerful tool called singleton object that ease the procedure we used to do with singleton classes in java.
Singletone Objects
object myObject
{
def +(x: java.lang.String) = x + " and "
}
def names = myObject + "Ehsan" + "Sana"
println(names)
//output Ehsan and Sana
Example
Still don’t know how compiler translates this:
Val myList = List(1,2,3)
We can create a new object just as we call a function with implenting apply method.
Reason: We are just trying to show the use of apply method as a handy way of closing the gap between functions and objects in Scala.
Apply Method
object List extends List
{
def apply[A](xs: A*): List[A]
//Creates a list with the specified elements.
}
Implementation of Apply Method for List
Lists
Maps
a fundamental structure in many functional languages is the immutable linked list.
Immutable Collections
1. val city= List(“Mashhad”,”Tehran”,”Abadan)
2. val city = “Mashhad”::”Tehran”::”Abadan::Nil
3. val city = “Mashhad”::(”Tehran”::(“Abadan”::Nil)))
4. val city = Nil.::(“Abadan).::(“Tehran”).::(“Mashhad)”
continue
def sum(xs: List[Int]): Int = if (xs.isEmpty) 0
else xs.head + sum(xs.tail)
Sums the elements of the list
Example
val map = Map("Tehran" -> "Iran" , "Paris" -> "France")
println(map.keys) // output: Set(Tehran, Paris)
Does the String class has a method ->? The answer is no.
We will see how this is translated…
Immutable Maps
partial functions obey pattern matching rules and syntax.
Instead of switch case structure here we have match and case
wide range of usage in collections and actors
Partial function is a trait
and its Constructor takes two types; Input type and output type.
It has two abstract values too; apply(v1 a: A): B and isDefinedAt(x : A): Boolean
Partial Functions
val p = new PartialFunction[Int, Any] { def apply(xs: Int) = xs match { case xs => 1/xs.doubleValue() case _ => 1/xs} def isDefinedAt(xs: Int) = xs match { case 0 => false case _ => true } }println(p(2)) //output: 0.5 println(p(0))// output: Infinity No exception is thrown
Example
Threads in java: shared objects and lock model
Synchronized and concurrency library
always control threads to not to let them have access on a shared object at a time, using blocks
Result: race conditions, deadlocks and non-determinism.
Threads
Scala suggest shared-nothing, message-passing model.
object firstActor extends Actor {
def act() {
for (i <- 1 to 3) {
println("act" + i)
Thread.sleep(1000)
}
}
firstActor.start() //output: act1 act2 act3
Actors
If actors do not have shared objects how do they connect each other???
So simple: sending message…
Problem
val echoActor = actor {
while (true)
{
receive { case msg => println("received message: "+ msg) }
}
}
console: echoActor ! “hi”
output: hi
Receive Method
Partial function
Does not stay on a receive line.
Messages goes to inbox waiting for actor to call receive.
receive invoke IsDefinedAt method to make sure the input is valid.
If input is valid, receive sends the it’s body to apply method otherwise it throw an exception.
How receive works?
val reciever = actor {
receive {
case x: Int => // Only Int is valid as input
println("Got an Int: "+ x)
}
}
reciever ! “hello world” //output: Nothing
receiver ! 4 // output: Got an Int: 4
Example