Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
109 views

Functional Programming: Int Double

This document provides an overview of functional programming concepts in Scala including: - Functions are first-class values that can be passed as parameters and returned from other functions. - Higher-order functions take functions as parameters or return functions. Common examples are map and filter. - Immutable values and avoidance of side effects are key principles of functional programming for simplicity and parallelization. - Core Scala types like List are immutable and use recursion with patterns like head/tail rather than iteration.

Uploaded by

hoanganh200870
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
109 views

Functional Programming: Int Double

This document provides an overview of functional programming concepts in Scala including: - Functions are first-class values that can be passed as parameters and returned from other functions. - Higher-order functions take functions as parameters or return functions. Common examples are map and filter. - Immutable values and avoidance of side effects are key principles of functional programming for simplicity and parallelization. - Core Scala types like List are immutable and use recursion with patterns like head/tail rather than iteration.

Uploaded by

hoanganh200870
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 27

Functional Programming

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

Functional programming: Functions are values In C++, values are


Primitive types int, double, etc. Structure/class values Pointers

A function is not a first class value in C++

Cannot create new functions in a running program

In a functional programming language, functions are first-class values


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

The design of the functional languages is based on mathematical functions


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

for the function


cube (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)

Functional Programming Languages


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

Functional Programming in Scala


Functions can be values


val num = 3.14 val fun = math.ceil _ fun(num) // prints 4

Functions can be anonymous...


(x : Int) => x * x

...just like numbers


3.14

Of course, can put function values into variables and then use them
val square = (x : Int) => x * x square(10) // prints 100

...again, just like numbers


val pi = 3.14 pi * 10 // prints 31.4

Why Functional Programming?


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

In Scala, but not in C++, a function can produce a new 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

Semicolons at the end of a line are optional


val x = 1 val y = 2 + // end line with operator to indicate that there is more to come 3

Everything is an object
1.to(10) // Apply to method to 1, returns Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Collections List (more in next lecture), Vector (similar to C++), Range

map works on any collection


1.to(10).map(x => x * x) // Type is inferred

Immutability

Immutable: Cannot change In Java, strings are immutable

"Hello".toUpper() doesn't change "Hello" but returns a new string "HELLO"

In Scala, val are immutable


val num = 3.14 num = 1.42 // Error

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

if (booleanExpression) expression1 else expression2

if/else is an expression, not a statement. Can be used in other expressions:


val x = (if (true) 2 else 4) * 3

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

def syntax for functions


def triple(x : Int) = 3 * x // same as val triple = (x : Int) => 3 * x

With recursive functions, also need to specify return type:


def fac(x : Int) : Int = if (x == 0) 1 else x * fac(x - 1)

Need def because the name is used on the right


val fac = if (x == 0) 1 else x * fac(x - 1) // fac not defined yet

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

Use :: to build lists


0 :: lst // List(0, 1, 4, 9)

List Functions

Use recursion for list functions


def sum(lst : List[Int]) : Int = if (lst.isEmpty) 0 else // NOTE: else must be on this line lst.head + sum(lst.tail)

Use :: to recursively build lists


def squares(n : Int) : List[Int] = if (n == 0) List(0) else n * n :: squares(n - 1)

Why This Isn't Inefficient

lst.tail doesn't make a new listit is a reference to the tail cell

Works because lists are immutable Requires garbage collection

Functions as Parameters

Consider the map function


val triple = (x : Int) => 3 * x (1 to 10).map(triple) // yields 3 6 9 12 ... 30

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?

Capturing the Enclosing Environment


Consider this function:


val n = 3 val fun = (x : Int) => n * x // What is fun(2)?

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

Huh? Let's call it:


val quadruple = mulBy(4) // the function (x : Int) => 4 * x

And let's call that:


quadruple(5) // yields 20

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)

Application: Event Handling


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

But without having to declare types:


var greeting = "Hello" // String is inferred greeting = 42 // Error

Contrast with scripting languages such as JavaScript


var greeting = 'Hello' // This is JavaScript greeting = 42 // Ok alert(greeting.length) // Runtime error: 42 doesn't have a length member

Type Inference 2

Can override inferred type (only to a supertype, of course)


var greeting : Any = "Hello" greeting = 42 // Ok

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

Function return type is inferred

If x is Int, then 42 * x is also Int

Exception: Recursive function


def fac(x : Int) = if (x == 0) 1 else x * fac(x - 1)

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

Parameter Inference From Context

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

Very useful when calling library functions


List(1, 2, 3).filter((x) => x % 2 == 0)

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

Ok to omit () around a single inferred parameter


List(1, 2, 3).filter(x => x % 2 == 0) List(1, 2, 3).sortWith((x, y) => x > y) // need () with 2 or more parameters

Use _ for a parameter that only occurs once in the body


List(1, 2, 3).filter(_ % 2 == 0) List(1, 2, 3).sortWith(_ > _)

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) } }

But calling is a bit ugly:


var x = 1 While (() => x < 10, () => { println(x); x+= 1 })

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) } }

Now the unsightly () => are gone from the call:


While ({ x < 10 }, { x += 1; println(x) })

Still unhappy about unsightly ( , ) in call.

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)

Huh? Simple example:


def mul(x : Int, y : Int) = x * y mul(3, 4) is 12 def mul2(x : Int)(y : Int) = x * y mul2(3)(4) is 12

What is mul2(3)? A function that is capable of eating 4, thus yielding 12

y : Int => 3 * y

The While Control Abstraction


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

Categories of List Methods


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

:: appends in front, :+ in back


3 :: List(1, 2) is List(3, 1, 2) List(1, 2) :+ 3 is List(1, 2, 3)

++ concatenate lists
List(1, 2) ++ List(3, 4) is List(1, 2, 3, 4) // same as :::

== and != compare lists


List("Hello", "World") == List("Hel" + "lo", "Wor" + "ld")

/: and :\ later

Operator Precedence and Associativity


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)

In C++, most operators are left-associative. Exception: Assignment


a = b = 3

Scala Operators

Function names can be any sequence of opchars: characters other than whitespace, A-Z0-

9()[]{}`'".,;

Operator precedence depends on first character


(all letters) | ^ & < > = ! : + * / % (all other special characters)

Operators ending in : are right associative; all others are left associative
a :: b :: Nil is a :: (b :: Nil)

Lists: Access by Position


Not very efficient for linked lists Index values are 0-based () are used for indexed accessnot []
List(17, 29)(1) is 29

slice takes sublist


List(2, 3, 5, 7).slice(1, 3) is List(3, 5)

Arguments to slice are


first index to include first index to exclude

See lab for drop take

Methods with Function Parameters


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))

Function can be shortenedsee next lecture Predicate = function returning Boolean

Some methods return a pair


List(2,3,5,7).partition(isEven) is (List(2),List(3, 5, 7))

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

The sum of the elements in List(a, b, c) is

a + b + c = 0 + a + b + c = ((0 + a) + b) + c

Use foldLeft or the /: operator


def sum(lst: List[Int]) = (0 /: lst) ((x, y) => x + y)

The /: indicates the tree shape


+ / \ + / \ + b / \ 0 a 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)) {_ * _}

The foldRight operator works right-to-left: a + (b + (c + 0))

mkString

toString produces the familiar List(1, 2, 3) What if we want 1 | 2 | 3?


lst.mkString("|")

One fewer separator than elements

What if we want [1 | 2 | 3]?


lst.mkString("[", "|", "]")

Nice attention to detail by the library designers

Comparing Functional and Imperative Languages

Imperative Languages:

Efficient execution Complex semantics Complex syntax Concurrency is programmer designed

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

You might also like