Exploring Languages with Interpreters
and Functional Programming

Chapter 2
Programming Paradigms

H. Conrad Cunningham

31 January 2019

Copyright (C) 2017, 2018, H. Conrad Cunningham

Acknowledgements: I created these slides in Fall 2017 and revised them in Summer 2018 to accompany what is now Chapter 2, Programming Paradigms, of the book Exploring Languages with Interpreters and Functional Programming.

Browser Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of January 2019 is a recent version of Firefox from Mozilla.

Programming Paradigms

Lecture Goals

Abstraction

Maxim:

Simplicity is good; complexity is bad.

Abstraction:

concentrating on the essentials and ignoring the details

remembering the “what” and ignoring the “how”

Make large complex problems understandable by decomposing into subproblems

Kinds of Abstraction

  1. Procedural abstraction: separate properties of action from implementation details

    Break complex actions into subprograms; develop program as sequence of calls

  2. Data abstraction: separate properties of data from representation details

    Identify key data representations; develop program around these and associated operations

Kinds of Subprograms

  1. Procedure (pure) takes zero or more arguments but does not return value; executed for effects

  2. Function (pure) takes zero or more arguments and returns a value; does not have effects

  3. Method is procedure or function associated with object in object-oriented program; object may be implicit parameter

Good practice to maintain distinction between procedure and function even if language does not

Programming Paradigm

Timothy A. Budd. Multiparadigm Programming in Leda, Addison-Wesley, 1995, page 3:

“a way of conceptualizing what it means to perform computation, of structuring and organizing how tasks are to be carried out on a computer.”

Primary Paradigms

Imperative Paradigm (1)

Imperative Paradigm (2)

    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }

Imperative Paradigm (3)

    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }

Imperative Paradigm (4)

    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }

Imperative Paradigm (5)

    int count =  0;
    int maxc  = 10;
    while (count <= maxc) {
        System.out.println(count) ;
        count = count + 1
    }

Imperative Paradigm (6)

To allow execution, the Java code above can be included in main method

    public class Counting {
        public static void main(String[] args) {
            int count =  0;
            int maxc  = 10;
            while (count <= maxc) {
                System.out.println(count) ;
                count = count + 1 
            }
        }
    }

Imperative Paradigm (7)

Declarative Paradigm (1)

Declarative Paradigm (2)

Declarative Paradigm (3)

Functional Paradigm (1)

Functional Paradigm (2)

    counter :: Int -> Int -> String 
    counter count maxc 
        | count <= maxc = show count ++ "\n" ++ counter (count+1) maxc 
        | otherwise     = ""

Functional Paradigm (3)

    counter :: Int -> Int -> String 
    counter count maxc 
        | count <= maxc = show count ++ "\n" ++ counter (count+1) maxc 
        | otherwise     = ""

Functional Paradigm (4)

    counter :: Int -> Int -> String 
    counter count maxc 
        | count <= maxc = show count ++ "\n" ++ counter (count+1) maxc 
        | otherwise     = ""

Functional Paradigm (5)

    main = do 
        putStrLn (counter 0 10) 

Functional Paradigm (6)

Functional Paradigm (7)

Relational Paradigm (1)

Relational Paradigm (2)

    counter(X,Y,S) :- count(X,Y,R), atomics_to_string(R,'\n',S).

    count(X,X,[X]). 
    count(X,Y,[])     :- X  > Y. 
    count(X,Y,[X|Rs]) :- X < Y, NX is X+1, count(NX,Y,Rs).

Relational Paradigm (3)

    counter(X,Y,S) :- count(X,Y,R), atomics_to_string(R,'\n',S).

    count(X,X,[X]). 
    count(X,Y,[])     :- X  > Y. 
    count(X,Y,[X|Rs]) :- X < Y, NX is X+1, count(NX,Y,Rs).

Above defines database consisting of clauses

count(X,X,[X]). defines fact

count(X,Y,[]) :- X > Y. defines rule

Relational Paradigm (4)

    counter(X,Y,S) :- count(X,Y,R), atomics_to_string(R,'\n',S).

    count(X,X,[X]). 
    count(X,Y,[])     :- X  > Y. 
    count(X,Y,[X|Rs]) :- X < Y, NX is X+1, count(NX,Y,Rs).

Relational Paradigm (5)

    main :- counter(0,10,S), write(S).

Relational Paradigm (6)

Procedural Paradigm (1)

Procedural Paradigm (2)

    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6 string interpolation
            incr()

Procedural Paradigm (3)

    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6+ string interpolation
            incr()

Procedural Paradigm (4)

    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6 string interpolation
            incr()

Procedural Paradigm (5)

    def counter(count,maxc):
        def has_more(count,maxc): # new variables
            return count <= maxc 
        def incr():
            nonlocal count     # from counter
            count = count + 1
        while has_more(count,maxc):
            print(f'{count}')  # Py 3.6 string interpolation
            incr()

Procedural Paradigm (6)

Primarily procedural languages:

Python, C, Fortran, Pascal, Lua, etc.

Modular Paradigm (1)

Modular Paradigm (2)

Each Python module is in separate file, creates separate name space

    # Python 3.6 file CountingMod.py
    count = 0                 # Notes 2,3
    maxc  = 10

    def has_more(count,maxc): # Notes 1,4
        return count <= maxc 

    def incr():               # Notes 1,4
        global count          # Note 5
        count = count + 1

    def counter():            # Notes 1,4
        while has_more(count,maxc):
            print(f'{count}')
            incr()

Modular Paradigm (3)

  1. Defines 3 module-level functions: has_more, incr, counter

  2. Defines 2 module-level global variables: count, maxc

  3. Initializes global variables: count, maxc

  4. Gives lexical scope in module to global variables & functions

    • globals count, maxc hidden in has_more by parameters with same names

    • globals count, maxc visible in incr, counter

  5. Declares count as global in incr for assignment

Modular Paradigm (4)

    from CountingMod import counter
    counter()

Modular Paradigm (5)

    import CountingMod

    CountingMod.count = 10
    CountingMod.maxc  = 20
    CountingMod.counter()

Modular Paradigm (6)

Other Programming Paradigms

Key Ideas

Source Code