Functional Programming: Int Double
Functional Programming: Int Double
Functional programming Scala basics Control and data structures Higher order functions and closures Scala Library Note: Try typing examples from this slide in Eclipse to have the "feeling"
Functional Programming
Can have variables that hold functions Can create new functions
Introduction
The design of the imperative languages is based directly on the von Neumann architecture
Efficiency is the primary concern, rather than the suitability of the language for software development
A solid theoretical basis that is also closer to the user, but relatively unconcerned with the architecture of the machines on which programs will run
Mathematical Functions
A mathematical function is
a mapping of members of one set, called the domain set, to another set, called the range set
A lambda expression specifies the parameter(s) and the mapping of a function in the following form
(x) x * x * x
Lambda expressions describe nameless functions Lambda expressions are applied to parameter(s) by placing the parameter(s) after the expression
((x) x * x * x)(2)
which evaluates to 8
Higher-order Function
A higher-order function is one that either takes functions as parameters or yields a function as its result, or both Function Composition: A function that takes two functions as parameters and yields a function whose value is the first actual parameter function applied to the application of the second Example
h = f g
which means
h (x) = f ( g ( x))
For
f (x) = x + 2, h (x) = (3 * x)+ 2
g (x) = 3 * x
Apply-to-all: A functional form that takes a single function as a parameter and yields a list of values obtained by applying the given function to each element of a list of parameters E.g. For
h (x) = x * x ( h, (2, 3, 4)) yields (4, 9, 16)
The objective of the design of a FPL is to mimic mathematical functions to the greatest extent possible The basic process of computation is fundamentally different in a FPL than in an imperative language
In an imperative language, operations are done and the results are stored in variables for later use Management of variables is a constant concern and source of complexity for imperative programming
In an FPL, variables are not necessary, as is the case in mathematics Referential Transparency: the evaluation of a function always produces the same result given the same parameters
Why Scala?
Multi-paradigm language Invented by Martin Odersky at EPFL, Lausanne, Switzerland Similar to Java Works with Java tools/libraries/etc We use the functional subset instead of OCaml We use the combinator parser library instead of Antlr Fewer things to learn => Can get deeper where we want to go
Of course, can put function values into variables and then use them
val square = (x : Int) => x * x square(10) // prints 100
Simpler and clearer programming style Often useful to pass functions as parameters
val numbers = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) numbers.map((x : Int) => x * x) // Prints Vector(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
In C++, you can also do this, but there are no anonymous functions.
vector<int> map(vector<int> values, int (*f)(int)) { vector<int> result; for (int i = 0; i < size; i++) result.push_back(f(values[i])); return result; } int square(int x) { return x * x; } ... res = map(numbers, square); // Must pass name of function
Scala Basics
Types Int, Double, Boolean, String Arithmetic like in C++: + - * / % Variable type is inferred:
val luckyNumber = 13 // luckyNumber is an Int
Function types:
val square = (x : Int) => x * x // square is an Int => Int
Everything is an object
1.to(10) // Apply to method to 1, returns Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Immutability
Pure functional programming: No mutations Don't mutatealways return the result as a new value Functions that don't mutate state are inherently parallelizable Important consideration in light of the end of Moore's Law
If/Else
Like ? : in C++ Type is the most specific supertype common to expression1, expression2
val x = if (true) 3 else "Hello" // type is AnyVal
Omitting the else yields type Unit (like void in C++); not useful in functional programming
Recursion
Iteration (while, for) can always be expressed as recursion To iterate is human; to recurse, divine (L. Peter Deutsch)
Lists
Very different from C++ linked lists. No iterators Three primitives: head, tail, :: (pronounced cons) A list is either empty (Nil) or has a head and tail
val lst = List(1, 4, 9) lst.head // 1 lst.tail // List(4, 9) lst.tail.tail.tail // Nil
List Functions
Functions as Parameters
Let's implement such a function. For simplicity, we only use sets and functions of Int Two parameters: List[Int], function (Int) => Int, returns List[Int]
def map(lst : List[Int], fun: (Int) => Int) : List[Int] =
Map of empty list is Nil, otherwise apply fun to lst.head and use recursion:
if (lst.isEmpty) Nil else fun(lst.head) :: map(lst.tail, fun)
Sample call:
map(List(1, 2, 3), (x : Int) => 3 * x)
A function describes a piece of behavior, such as What should map do with each element in lst?
n is not defined in the scope of fun, but that is ok. In the body of a function, you can use any
variable from the enclosing scope. Doesn't seem a big dealn is immutable, so it will always be 3. But consider this:
def mulBy(n : Int) = (x : Int) => n * x
Each call to mulBy yields a different function. Each function has a different value of n Closure = function + binding of its free variables (i.e the variables that are not defined locally in the function)
val textArea = new JTextArea(20, 50) val button1 = new JButton("Click Me!") button1.addActionListener((e : ActionEvent) => { textArea.append("I was clicked\n") })
Closure captures textArea Full code here (if you are interested) Tedious in Java; requires inner class
final JTextArea textArea = new JTextArea(20, 50); button1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { textArea.append("Hello\n"); } };
Type Inference
Scala is strongly typed. Any value has a type guarantee. Just like C++:
char* greeting = "Hello"; greeting = 42; // Error
Type Inference 2
Parameter types must be specified (because they are not initialized when they are declared)
def mystery(x) = 42 * x // Error def mystery(x : Int) = 42 * x // Ok
Can't get type of right hand side without knowing type of fac Limitation of Scala: Other languages (e.g. Haskell) can infer recursive types through unification
When a function parameter type is known, you can supply an anonymous function without specifying its parameter types
def twice(f: (Int)=>Int, x : Int) = f(f(x)) twice(x => 42 * x, 3) // Ok, x : Int is inferred from context
List[A].filter (p : (A) => Boolean) : List[A] A is Int since List(1, 2, 3) is a List[Int] f must be (Int)=>Boolean x must be Int
Parameter Simplifications
Control Abstractions
Methods such as map and filter have as argument a function (i.e. code) A while loop has two arguments: a condition (code) and a body (code) Could we implement while in Scala? Sure:
def While(cond: () => Boolean, body: () => Unit) { if (cond()) { body(); While(cond, body) } }
By-Name Parameters
Control abstraction = User or library function that looks to programmers like a language mechanism Want nice syntax, e.g. {} for blocks without () => Use by-name parameters
def While(cond: => Boolean, body: => Unit) { // Not () => if (cond) { // NOTE: No () in call body; While(cond, body) } }
Currying
Currying = Turning a function that takes two arguments into a function that takes one argument. That function returns a function that consumes the second argument. (Named after the logician Haskell Brooks Curry)
y : Int => 3 * y
def While(cond: => Boolean)(body: => Unit) { if (cond) { body; While(cond)(body) } } While (x < 20) { x += 1; println(x) }
Trick #1: By-name parameters Trick #2: Currying * Note: While {x < 20} also works
Scala Documentation
Online at http://scala-lang.org/ Be smart: Download and install it locally Be smart: Bookmark it Use text field in upper left corner to filter classes
Basic methods length head tail isEmpty Operators :: :+ ++ == != /: :\ Access by position (n) take drop dropRight slice indexOf lastIndexOf Methods with unary predicates count exists dropWhile filter find
findIndexOf forall partition remove span takeWhile Methods with unary function map reverseMap flatMap foreach Methods with binary predicate sort Methods with binary function reduceLeft reduceRight foldLeft foldRight Other intersection union zip zipAll zipWithIndex mkString
List Operators
++ concatenate lists
List(1, 2) ++ List(3, 4) is List(1, 2, 3, 4) // same as :::
/: and :\ later
On this calculator, what do you get when you type 1 + 2 * 3? What do you get in C++? Precedence: Which operator is executed first?
(1 + 2) * 3 1 + (2 * 3)
Associativity: If the same operator occurs twice, is the left or right one executed first? Does 1 2 - 3 mean
(1 - 2) - 3 1 - (2 - 3)
Scala Operators
Function names can be any sequence of opchars: characters other than whitespace, A-Z0-
9()[]{}`'".,;
Operators ending in : are right associative; all others are left associative
a :: b :: Nil is a :: (b :: Nil)
Not very efficient for linked lists Index values are 0-based () are used for indexed accessnot []
List(17, 29)(1) is 29
Workhorse functions of the library You already saw filter, sort, map Others explored in lab Instead of looping, build a function and pass it to one of these methods
def randList(len : Int, n : Int) = (1 to len).map((x : Int) => gen.nextInt(n))
Tuples
A pair is an example of a tuple If S, T, U are any types, then we have tuple types (S, T), (S, T, U) Ex. ("Hello", 1729) is an instance of (String, Int) Use methods _1 _2 etc. to access members (not zero-based!)
("Hello", 1729)._2 is 1729
Convenient if a method returns more than one piece of information Don't use tuples if the data has semantics. Ex. Don't use (day, month, year). Make (or use) a Date class.
Folding
a + b + c = 0 + a + b + c = ((0 + a) + b) + c
The first argument of the folding function is the partial answer; the second is the new list value to be considered To recurse may be divine, but not to recurse is even better:
def fac(n : Int) = (1 /: (1 to n)) {_ * _}
mkString
Imperative Languages:
Functional Languages
Simple semantics Simple syntax Inefficient execution Programs can automatically be made concurrent
Summary
Functional programming languages use function application, conditional expressions, recursion, and functional forms to control program execution instead of imperative features such as variables and assignments Purely functional languages have advantages over imperative alternatives, but their lower efficiency on existing machine architectures has prevented them from enjoying widespread use