Você está na página 1de 15

CPE 657

Topics
What is functional language?
Components of ML

Functional Programming Language

Operators, if-then-else, types, lists, function definition


Patterns, local environment, exception
Curried functions, polymorphic functions, higher-order functions

Yongyuth Permpoontanalarp

Based on lectures by Jeff Ullman from Stanford

Department of Computer Engineering


KMUTT

slide 1

Functional languages : declarative


programming

Standard ML
Standard ML developed at Edinburgh Univ. at '84-'88

Declarative programming vs. Imperative programming

Standard ML97 is a revised version of SML


SML/NJ is a compiler for SML97 and developed at Bell labs and
Princeton Univ.
http://www.smlnj.org/

Declarative : say what solution is


Imperative : say how the solution is (step by step)

Declarative programming:
Logic programming eg. PROLOG
Functional programming eg. ML

Key features of ML

slide 2

Functional language
Curried functions
Higher order functions
Polymorphic : operations for various types
Abstract data types
Strong typing

No reassignment to variables
After a variable is given a value, then no change
Referential transparency : easy to formal analysis

slide 3

slide 4

Why declarative programming?


Step-by-step operations
Imperative prog.

Functional Language

Mathematics

Program = a collection of functions


1. Definition of functions
2. Application of functions
Function = expression which takes input and produces
output

Declarative prog.
Functional prog. => Lambda calculus
Logic prog. => Logic

Program construction = a mathematical formulation

Not step-by-step operations

Lambda calculus = theory for recursive functions


Formal analysis is easier

f(input)=output
f(a1,,an)=exp[a1,,an]

Computation = evaluating expressions (reduction)


Core idea is that almost everything behaves as
function : taking inputs and return outputs

Program correctness
Program transformation : partial reduction for efficiency

But slower than imperative prog.


slide 5

slide 6

Example

Computation in functional language

fun double x = 2 * x;
(* definition *)
double 3;
(* application *)
=2*3
=6
fun times4 x = double(double x);
(* defn *)
times4(5) = double(double 5)
(* app *)
= double(2 * 5)
= double(10)
= 2 * 10
= 20
slide 7

slide 8

Higher-order & polymorphism


functions

Types

Higher-order functions : functions that take functions as


input arguments and produce functions as output

Abstract data types


To build new types
To restrict access to new objects of new types by a fixed set of
operations

Flexible application of the input function


Abstraction : skeletons of computation

Strong typing

Polymorphism : functions that can take arguments of


various data types

Types of values and variables are decided at compile time


Thus, no type conversion (or change) at runtime

Single function for stacks of integers, reals, strings, etc.


Push and Pop
Code sharing

slide 9

Using ML

slide 10

Variables in ML

Interactive mode : interpreter


After a user types an expression, ML responds with the
value and its type

We can assign a value to variables foo and bar


Called binding : var value
val foo = 5;
val foo = 5: int
val bar = 7;
val bar = 7: int
The value of the variable is .
foo + bar;
val it = 12 : int

5;
val it = 5 : int
abc;
val it = abc : string
it means the previously typed expression
Semicolon must end all expressions
slide 11

slide 12

Operators

Concatenation of strings

Arithmetic operators
Infix: +, , * , /, mod
~ denotes unary minus
Comparison operators
<> means not equal
=, <=, <, >, >= as usual
Logical operators
andalso, orelse, not

Operator ^ denotes string concatenation

~3*(~4);
val it = 12 : int

foo ^ bar;
val it = foobar : string

4 <= 3;
val it = false : bool
love < war;
val it = true : bool

3<4 andalso 5<4;


val it = false : bool

slide 13

If-then-else expression

slide 14

Types

It is an expression, not a statement


If E then F else G
= f(E,F,G)
Compute expression E
If true then return F
If false then return G

Basic types are integer, real, string, char, boolean, unit


Real = floating points
Bool has only true and false
Char = #x means character x
Unit = a special null type which has one value ()
Empty value

val x = if 3<4 then 5 else 6;


val x = 5 : int

slide 15

slide 16

Types (cont.)

Type determination
ML will determine the type for most expressions using
clues such as the types of arguments

#Z < #a;
val it=true:bool
abc <= ab;
val it=false:bool

Variables, inputs and output of functions

Types of operators and operands


=>

Many ML operators like * are overloaded; they can apply


to operands of various types

fun hello() = hello world;


val hello = fn: unit string

Integers, reals

ML views operators as applying to a single operand


Binary infix operator : a pair of items
3 * 4 means *(3,4)

slide 17

slide 18

Type determination

Type determination

1. In arithmetic operator, types of operands and result of


the operators must all agree

4. Types of passing arguments and declaring parameters


of function must agree

In a+b, if a and b are real, then + produces real

2. In arithmetic comparison, types of all operands must


agree

f(value)

5. Types of expression defining function and return of the


function must agree

In (a<=10), a must be integer

3. In conditional expression if E then F else G, result of


expression and types of F and G must all agree

Input
fun f(input:type)

val x = if 3<4 then 5 else 6;

Output
fun f(input:type1):type2 = exp

6. If type of overloaded operator is unknown, it is by


default integer

slide 19

slide 20

Type conversion (coercion)

ML identifiers

There are a few operators that do type conversion


Integer to real : real(x)
Real to integer : floor(x)
Integer to char : chr(x)
3.14 * real(2);
val it = 6.28 : real
chr(35);
val it = # : string

Identifier = name of variables or functions


Identifiers ML may be formed in one of two ways
1. Alphanumeric (start by letter)

a,b,c,,z, A,B,C,Z, a1, a2,., a_11


Type variables: a, b

2. Symbolic (start by symbol)

$, ?, &, @,

At most, 20 characters
Variables can hold not only data but also functions

slide 21

slide 22

Tuples

Two important complex data types


Basic types : integer, real, string, char, boolean, unit
Complex types : tuples and lists

A parenthesized list of values of any (mixed) type


Like product of many different types
(4, 4.0, four);
val it = (4, 4.0, four) : int * real * string
To extract an ith component of a tuple with the #i
operator where i is integer
#2(4, 4.0, four);
val it =4.0 : real

slide 23

slide 24

Lists

Operators on lists

A sequence of values of the same type surrounded by


square brackets
[a, b, c];
val it = [a, b, c] : string list
[(1,2), (3,4)];
val it = [(1,2), (3,4)] : (int*int) list

hd and tl extract the head and tail of list


Head=the first element, Tail= the remaining list

hd([1,2]);
hd [];
val it = 1 : int
error
tl([1,2]);
tl [];
val it = [2] : int list
error
tl [1];
val it = [] : int list
Parenthesis is not needed for arguments of oneargument function

The empty list is [] or nil

slide 25

Operators on lists

slide 26

Constructors

:: is the constructor operator which connects head and


tail to form a new list
1::[2,3];
val it = [1,2,3] : int list
@ is the concatenation operator for lists
[1]@[2,3];
val it = [1,2,3] : int list

Constructor = operator which can be used to build the


following
Data
Type
Exception

slide 27

slide 28

Function definition
1.
2.
3.
4.

Function application
FE

Keyword fun
Function name and formal parameters
=
Expression giving the value returned by the function

where F is a function name and E is an expression

Evaluating expression E and then applying to function F


fun square(x:real) = x*x;
val it=fn : real real
val x=3.0;
val y=4.0;
square(x+y);
val it = 49.0 : real
square(square(3.0));
val it = 81.0 : real

fun cube(x:int) = x*x*x;


val cube = fn : int int
For a non-function, ML responds with its value + type
For a function, ML responds with the type
slide 29

Function application

slide 30

Patterns

Function application can be used as operand


3.0 + square(3.0);
val it = 12: real

A powerful technique to define a function with multiple


cases of input arguments
A case = a pattern

The first pattern that matches the input is taken

Function application has higher precedence than any of


the arithmetic operators
square(x)+y means (square(x))+y

slide 31

slide 32

Example of pattern

General form of function declaration

Program 1: member(element,list) = boolean

1.
2.

fun member(x, nil) = false


(* base case *)
| member(x, y::ys) =
(* recursive case *)
if x=y then true
else member(x, ys);
val member = fn: a * a list bool

Keyword fun
One or more expressions of the form
pattern = expression, separated by |
fun pattern1=expression1 |
pattern2=expression2 |

patternn=expressionn

Type variable a mean an equality type

Pattern = function name + parameters

Any type in which = is defined eg. integers, reals, etc

Each parameter may be an expression

Expression may use the variables that appear in the


parameters

Cannot do the following in the second pattern


member(x, x::xs) since cannot use a variable twice in a pattern

slide 33

Local environments

Example of local environment


Program 2: minmax(list)=(min,max)
fun minmax([x:int]) = (x,x)
| minmax(x::xs) =
let
val (low,high) = minmax(xs) (* recursion on short list *)
in
if x<low then (x,high)
(* new low *)
else if x>high then (low,x)
(* new high *)
else (low,high)
end;
val minmax= fn : int list int * int
No case for the empty list

Let.inend construct allows use to make local or


temporary declarations using val or fun
It goes away after the end
let
val var1=expression1;
val var2=expression2;
val varn=expressionn
in
expression
end;

slide 34

expression

slide 35

slide 36

Exception of function

Exception of function

How to handle errors in input data to functions?

1. Define our own exception names


2. Raise them in program when an exceptional condition is
discovered
3. Handle exception (catch exception)

Many functions are partial

They are defined for some kinds of input data only


a div b is not defined when b=0
Thus, a div 0 => an uncaught exception error

Writing functions for your specific input data

For other data, use exception handling

slide 37

How to do Exception

slide 38

Handling exception

Define it
exception EmptyList;
EmptyList is the name of an exception

Catch exceptions
<expression> handle <match>
Expression = function definition that we want to handle
exceptions

fun minmax([x:int]) = (x,x)


| minmax(nil) = raise Emptylist
| minmax(x::xs) =
let

Match = one or more clauses of the form


<pattern1> => <expression1> |
<pattern2> => <expression2> |

<patternn> => <expressionn>

where pattern describes exception name to catch

slide 39

slide 40

Example

Statement lists

If <expression> before handle returns


A non-exception: then forward it as output
An exception: then find the pattern that matches it and
return the corresponding expression

It is useful to execute a sequence of two or more statements


(<first-expression>; ; <last-expression>)
This list is an expression and produce a value which is the
last expression

Program 3: safeminmax(list) = (result,(min,max))

fun foo(i) = (
print(The value );
print(i:int);
print( was given\n) );
val foo = fn : int unit

fun safeminmax(L) = (ok,minmax(L))


handle EmptyList => (EmptyList, (0,0));
val safeminmax = fn : int list string * (int * int)

slide 41

Curried functions

slide 42

Curried functions
Normal function : takes one argument as a tuple
Curried function : takes more than one parameter

Curried function = a method to do an abstract


computation: specialization or partial instantiation
A specialized function which fixes some input
parameters but varies the others

fun add(x,y) = x+y:int;


val add = fn : int * int int

(* normal function *)

fun addc x y = x+y:int;


val addc = fn : int int int

(* curried function *)

Note that int int int means int (int int)


Note that no parentheses over inputs of curried function
slide 43

slide 44

Curried functions

Polymorphic functions

val add3 = addc 3;


val add3 = fn : int int
add3(10);
val it = 13 : int

Polymorphism = the ability of a function to allow


arguments of different data types (in the same
function)

Fixing one input to 3


addc = generalization but add3 = specialization

Eg. Stacks
No restriction on types of data ie. a list
Code sharing or generic function

By the type determination algorithm in ML

slide 45

slide 46

Example

Example (polymorphism + curried)

fun identity (x)=x;


val identity=fn:a a

Program 4: ins c (x,l1) = l2

identity(2);
val it=2:int

fun ins gt (x,nil) = [x]


| ins gt (x, y::ys) =
if gt(x,y) then y::ins gt (x,ys)
else x::y::ys;
val ins=fn : (a * a bool) a * a list a list

To insert element x into sorted list l1 of any data type


ins c (x,l) where c=comparison operator for the data

identity(hello);
val it=hello:string

Note : use curried style of function to deal with gt


Need specific gt for each kind of data

slide 47

slide 48

Example

Example

Note op converts infix operator to prefix-style function

Program 5: >>(p1,p2) = boolean


where p1 and p2 are pairs of integers

fun >>((a:int,b),(c,d)):bool=
if a>c orelse (a=c andalso b>d) then true
else false;

ins (op >) (15,[11,20]);


[11,15,20]
ins (op >) (g,[a,b]);
[a, b, g]

>>((2,3),(1,4));
val it = true : bool
ins >> ((3,3),[(1,3),(2,4),(5,4)]);
val it = [(1,3),(2,4),(3,3),(5,4)] : (int * int) list
slide 49

slide 50

Example

Example

Program 6: isort c l1 = l2
To sort list l1 of any type, c=comparison operator,
l2=output sorted list

Integer sorting and pair of integer sorting by partial


instantiation
val iisort = isort (op >);
val iisort = fn : int list int list
iisort([5,3,7]);
val it = [3,5,7] : int list

fun isort gt nil = nil


(* curried style *)
| isort gt (x::xs) =
ins gt (x, (isort gt xs));
val isort = fn : (a * a bool) a * a list a list

val pisort=isort >>;


val pisort = fn : (int * int) list -> (int * int) list
pisort [(1,3),(4,2),(3,5)];
val it = [(1,3),(3,5),(4,2)] : (int * int) list

isort (op >) [3,1,4];


= ins (op >) (3, (ins (op >) (1, (ins (op >)(4, nil)))))
isort (op >) [1,4]
slide 51

slide 52

Example

Higher-order functions

Note that functions ins and isort are polymorphic

Normally, the input and output of functions is


elementary data
But functions can take functions as arguments and/or
produce functions as values

But iisort and pisort are not !!!!

Generalization = polymorphic + curried

higher-order functions

Skeleton of computation
Three higher-order functions

Specialization = non-polymorphic
(bound with some specific data)

map
reduce
filter

slide 53

Map

slide 54

Map (more example)

To apply any function to each element of a list and


returns the resulting list

map (fn x => x+1) [1,2,3];


fn is an anonymous function

[1,2,3,4] with f = [f(1),f(2),f(3),f(4)]

We can create specialization by fixing F

fun map F nil = nil


(* in curried style *)
| map F (x::xs) = F(x)::map F xs;
val map = fn : (a b) a list b list
fun ++ x = x+1;
val ++ = fn : int int
map ++ [1,2,3];
val it = [2,3,4] : int list

val listSq = map (fn x => x*x:int);


val listSq = fn : int list int list
listSq([1,2,3,4,5];
val it = [1,4,9,16,25] : int list

Note that map is polymorphic

slide 55

slide 56

Reduce

Reduce (more example)

To put an operator between all elements of a list and evaluate the


resulting expression

Create a function to count the list member by fixing


function F
F

[2,3,4] with * and 1 to get (2*3*4)*1 = 24


reduce (f,g) l where g=initial value
(* in curried style *)
fun reduce (F,g) nil = g
| reduce (F,g) (x::xs) = F(x,(reduce (F,g) xs));
F(head, result-of-tail)

val reduce = fn : (a * b b) * b a list b


Result: reduce (F,g) [d1,d2,,dn] = F(d1,F(d2,F(dn,g)))
Example: reduce (op *,1) [2,3,4,5];
val it = 120 : int
It produces 2*(3*(4*(5*1)))

val length = reduce (fn(x,y) => y+1, 0);


val length = fn : a list int
length([a, b, c]);
val it = 3 : int
It produces fn(a, fn(b, fn(c, 0)))

reduce (*,1) [2]


= *(2, (reduce(*,1) []) )
= *(2, 1)

slide 57

Filter : to remove data from list

slide 58

Conclusion

Let predicate be a function

Functional language like ML is a powerful


programming lang.

Input=element and Output=boolean

Filter is a function that takes predicate P and a list and


produces list of elements that satisfying P

fun filter(P,nil) = nil


| filter(P,x::xs) = if P(x) then x::filter(P,xs)
else filter(P,xs);
val filter = fn : (a bool) * a list a list
filter (fn(x) => x>10, [1,10,23,5,16]);
val it=[23,16] : int list

slide 59

Declarative style
Curried function
Polymorphism
Higher-order function

slide 60

Você também pode gostar