Document Sample
Graphics Powered By Docstoc
					159.331 Programming Languages
         & Algorithms
              Lecture 17 - Functional
          Programming Languages - Part 1
            Functions, Lists, Types and
             Referential Transparency
159.331              Prog Lang & Alg       1
             Declarative Languages
• Imperative (and OO) languages focus on how a
  computation is done.
• They allow the programmer to specify (exactly) a recipe
  or procedure to follow to obtain a result
• This is done (inevitably) with a close consideration of
  what the hardware is capable of
• Languages that focus on “what” is to be done, rather
  than a detailed “how”, are declarative languages (we
  “declare the problem” rather than specifying detailed
• Two main examples of declarative languages are the
  functional languages and the logic programming
   159.331              Prog Lang & Alg              2
                 What vs How
• Not always completely clear and simple
• Nevertheless a useful split in the philosophy of
  thinking about these languages
• Declarative languages are usually slower (harder to
  implement efficiently)
• Naïve implementations can be very slow indeed (orders
  of magnitude slower) compared with good ones
• Compare this with the imperative paradigm where it is
  usually hard to make a really bad implementation
• However good declarative implementations can get
  close to the potential speed and performance of
  imperative programs
   159.331              Prog Lang & Alg             3
• If declarative is so potentially inefficient why
  use it?
• Because a declarative program may be very
  much easier to write than a corresponding
  imperative one for the same problem
• When the programmer has become a more
  expensive asset than the computer, this makes
• Sometimes it may suffice just to use declarative
  programming for a rapid high level prototype,
  that other programmers can turn into an
  efficient imperative or OO program later.
  159.331            Prog Lang & Alg           4
 Functional Programming Principles
• Generally offer a higher level more abstract notation
  than imperative languages
• Functional programs are generally close r to a
  mathematical notation - so easier to reason about with
  having to worry about implementation details
• Imperative languages use a “state” that is repeatedly
• Imperative procedures for example may change the
  global state of the program (known as side-effects)
• The main functional programming idea is to get rid
  of these side-effects of functions

   159.331               Prog Lang & Alg               5
• A functional or applicative language is based
  on the evaluation of expressions built out of
  function calls (applications)
• A function is like a pure mathematical
  function: it maps value s from its (input)
  domain to values of another (co)domain
• A function computes a certain value based on
  its input parameters - and has no other effect
• For example application of the “+” function
  as in 2 + 3 computes the value 5 and does
  nothing else
  159.331            Prog Lang & Alg           6
• This lack-of-side-effects property is known as referential
• It means the result does not depend upon when the
  function is called, but only on how (that is: “with what
  argument values”)
• In an imperative language the result of f(x) + f(x) need not
  be the same as 2 * f(x) because f might have side
  effects, such as changing x
• In a functional language the two expressions are always
  equal - and the compiler is allowed to make assumptions
  on this basis
• Generally the referential transparency makes the language
  easier to understand (both for the human programmer and
  for the compiler software)
    159.331               Prog Lang & Alg               7
            No assignment statements!
• Is this overly restrictive? No, since
• we can simulate using parameter mechanisms:
        function P(n: integer) -> SomeType;
         x: integer := n +7;
        begin                               Where:
         x:= x * 3 + 1;                     function Q(x:integer) -> SomeType;
        return 5 * g(x);                    begin
                                              Return 5 * g(x);
• Can become:
        function P(n: integer) -> SomeType;
         x: integer := n +7;
         return Q(3*x+1) % simulate x := 3 * x + 1

  159.331                        Prog Lang & Alg                          8
• A similar technique can be used to simulate globals
• This is not the main point of functional programming, but
  sometimes it is useful.
• Modifying data structures is a problem in functional
   – In an imperative language we just change an element
   – In a functional language we need a function to copy the
     elements except for the modified one, which is substituted -
     potentially very slow
• Similar problems arise for functional languages in
  interacting with external state (I/O)
• Remember however that the compiler is allowed to
  optimize potential inefficiencies into imperative code
  internally to make the executable.
   159.331                   Prog Lang & Alg                    9
• Functional languages are based on the evaluation of
  expressions consisting of function applications
• Global state variables and assignments are eliminated,
  so value returned by a function depends only upon its
• State information is passed explicitly through function
  arguments and results

• We will look at various functional language features -
  example based on Miranda language syntax.

  159.331               Prog Lang & Alg              10
• Takes zero or more arguments and computes a result. An
   celsius :: num -> num                       || Type declaration
   celsius f = ( f - 32) * 5 / 9               || Convert Fahrenheit to Celsius
• First line declares celsius as a function taking one numeric argument
  and returning a numeric value.
• Second line implements this function and converts temperatures
  using the given formula. Invoke using:
   celsius 68               results in 20
   celsius (-40)            results in -40

• Note the terse Miranda syntax, not even any parentheses around the

     159.331                           Prog Lang & Alg                            11
            Recursive Functions
• Play an important role in functional languages
• Traditional factorial (x!) example:
  fac :: num -> num
  fac x = 1, if x = 0                     || fac 0 = 1
  fac x = x * fac (x-1), otherwise        || recursive call
• The definition of fac involves two separate
  equations, each containing a condition
• The system will use the textually first one
  whose condition is true
  159.331               Prog Lang & Alg                       12
    Alternative Imperative factorial
   function fac( n: integer);
   var i, r, integer; % r will eventually contain the result
   r := 1             % compute n * (n-1) * (n-2) * … * 1:
   for i = n downto 1 do
     r := r * i
   return r;
Note that this uses a state variable r and is arguably
 more cumbersome than the recursive Miranda version
   159.331                 Prog Lang & Alg                     13
• Most important data structure in most functional
• Different from arrays as lists can be of unspecified
  (unknown) length
• A Miranda list contains zero or more elements of the same
   [1, 4, 9, 16]                 || list of four integers
   [1..10]                       || list with 10 integers (1,2,3,…10)
   [‘u’, ‘f’, ‘o’]               || list of three characters
   []                            || empty list
   [ [2, 4, 6], [0, 3, 6, 9] ]   || list of two lists of integers (nested)
     159.331                      Prog Lang & Alg                        14
            List Comprehension
• A notation in many functional language s for
  defining lists in a syntactically similar way we
  do for sets in mathematics
  [x | x <- [1..10] ; x mod 2 = 1 ]
• Results in [1,3,5,7,9]
• It denotes the set of all odd numbers between 1
  and 10. The <- symbol is used for the set-
  element symbol and the list comprehension is
  read as “the list of all elements x between 1 and
  10 for which x mod 2 equals 1”
  159.331                Prog Lang & Alg        15
                      List Operations
•   Often many operations supplied, simple ones are:
•   head “hd” selects the first element
•   tail “tl” selects the rest (everything except the head)
•   cons “:” inserts an element
    –   hd [10, 20, 30]   results in 10
    –   tl [10, 20, 30]   results in [20, 30]
    –   5:[ ]             results in [5]
    –   3:[4,5,6]         results in [3,4,5,6]

        159.331            Prog Lang & Alg           16
                More List Operations
• length of a list; reverse a list, concatenate lists, select
  particular elements from a list…
• Usually a particular language will have all these built in.
  Can implement ourselves using recursive functions:
   length x = 0, if x = [ ]
   length x = 1 + length ( tl x ), otherwise
   concatenate x y = y, if x = [ ]
   concatenate x y = ( hd x) : concatenate (tl x) y, otherwise
• Typical recursive definitions - the first line of each
  provides the “escape-hatch” or termination condition
• In Miranda:      #[3..7]             gives 5 and
                   [1,2,3]++[4,5]      gives [1,2,3,4,5]
     159.331                   Prog Lang & Alg                   17
• We can of course build lists ourselves in
  imperative languages or even more easily in
  OO languages - often part of a system library
• It will typically be built from chunks of
  dynamically allocated memory tied together
  with pointers and the operations implemented
  through pointer manipulation
• In functional languages we do not need to be
  aware of the pointers and memory allocation
• The language’s run time system will take care
  of all this for us - probably with a built-in
  garbage collector
  159.331           Prog Lang & Alg          18
             Types and Polymorphism
• Functional type systems often very different from
  that in imperative languages
• eg Ada uses strong static typing with explicit
• Most functional languages use either no (weak)
  typing, dynamic typing, or implicit strong typing
• Functional languages often also provide flexibility of
  polymorphic functions
• Lisp (the first functional language) used no typing at
  all (everything treated the same) - this is useful for
  flexibility but disallows the compiler from providing
  early (compile-time) warnings
   159.331               Prog Lang & Alg               19
• Miranda and modern functional languages use implicit
  static typing (ie type information is deduced and
  checked for consistency by a type checker)
• For example, in:         triple x = 3 * x
• The type checker can deduce that x must be a number
  because it is used in multiplication. It can also conclude
  that the result of triple x is a number as well, so the type
  of this function is:
   triple :: num -> num
• We will use the -> notation to denote “maps to”
• In some systems such as ML, implicit typing is used
  but the programmer can chose to give the type
  information declaration explicitly, (which can be
  checked for consistency by the checker)
   159.331                 Prog Lang & Alg                20
            Polymorphism again…
• Recall that a polymorphic function accepts
  actual parameters of different types for a single
  formal parameter
• This is subtly different from an overloaded
• Polymorphic function is a single function not
  multiple functions with the same name
• Consider pair x y = [x,y] a function to
  build a list from two arguments

  159.331             Prog Lang & Alg            21
• In a functional language we can use pair as
  follows (using => to denote “results in”:
  pair 1 2        => [1,2]
  pair True False => [True, False]
  pair [ ] [2]    => [ [ ], [2] ]
• There is a single definition of the function pair,
  but it can be invoked with different types as long
  as both arguments have the same type
• In an imperative language we would typically
  have to write multiple overloaded
  implementations of the function or worse still,
  multiple functions with different names…
  159.331              Prog Lang & Alg          22
                      Type Variables
• How do we express the type of the function pair ?     We
  introduce a type variable.
• Within a type declaration a type variable can denote any
  type but it must be the same type throughout the
• The function pair has the following type:
   pair ::  -> ( -> [] )
• This says that pair takes two arguments of type  and
  returns a list of ’s -good reasons later for not (, )->[]
• This is static & strong and rules out (at compile time):
   pair 1 True        || arguments must be of same type
   5 + (pair 1 2)     || result is a list , not a number

    159.331                   Prog Lang & Alg              23
         Functional Part 1 - Summary
• Functional programs consist of functions that map input values
  from one domain onto output values of another (co)domain,
  much as in mathematics. Pure functional languages lack
  imperative features such as assignment and repetitive statements.
  Also unlike most imperative languages, functions in functional
  languages cannot have side-effects.
• Pure functional languages are referentially transparent, which
  means that the result of a function application does not depend
  on when the function is called but only on the arguments of the
• Referential transparency can make programs easier to read,
  transform, parallelize and prove correct.
• We covered lists, types and polymorphism …
• See Bal & Grune Chapter 4, Sebesta Chapter 15.
   159.331                   Prog Lang & Alg                   24

Shared By: