Exploring Languages with Interpreters
and Functional Programming

Chapter 2
Programming Paradigms
Scala Version

H. Conrad Cunningham

29 January 2019

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

Acknowledgements: I created the original version of 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. In Spring 2019, I created this Scala version.

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)

    var count : Int =  0
    var maxc : Int  = 10
    while (count <= maxc) {
        println(count)
        count = count + 1
    }

Imperative Paradigm (3)

    var count : Int =  0
    var maxc : Int  = 10
    while (count <= maxc) {
        println(count)
        count = count + 1
    }

Imperative Paradigm (4)

    var count : Int =  0
    var maxc : Int  = 10
    while (count <= maxc) {
        println(count)
        count = count + 1
    }

Imperative Paradigm (5)

    var count : Int =  0
    var maxc : Int  = 10
    while (count <= maxc) {
        println(count)
        count = count + 1
    }

Imperative Paradigm (6)

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

    object CountingImp {
        def main(args: Array[String]) {
            var count : Int =  0
            var maxc : Int  = 10
            while (count <= maxc) {
                println(count)
                count = count + 1
            }
        }
    }

Imperative Paradigm (7)

An implementation using val and type inference

    object CountingImp2 {
        def main(args: Array[String]) {
            var count =  0  // use type inference 
            val maxc  = 10  // make val nor var
            while (count <= maxc) {
                println(count) 
                count = count + 1 
            }
        }
    }

Imperative Paradigm (8)

Declarative Paradigm (1)

Declarative Paradigm (2)

Declarative Paradigm (3)

Functional Paradigm (1)

Functional Paradigm (2)

    def counter(count: Int, maxc: Int): String =
        if (count <= maxc)
            count.toString ++ "\n" ++ counter(count+1,maxc)
        else
            ""

Functional Paradigm (3)

    def counter(count: Int, maxc: Int): String =
        if (count <= maxc)
            count.toString ++ "\n" ++ counter(count+1,maxc)
        else
            ""

Functional Paradigm (4)

    def counter(count: Int, maxc: Int): String =
        if (count <= maxc)
            count.toString ++ "\n" ++ counter(count+1,maxc)
        else
            ""

Functional Paradigm (5)

    object CountingFun {
        def counter(count: Int, maxc: Int): String =
            if (count <= maxc)
                count.toString ++ "\n" ++ counter(count+1,maxc)
            else
                ""
        def main(args: Array[String]) {
            println(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)

    object CountingProc {
        def counter(count: Int, maxc: Int) {
            var kount = count  // cannot change parameter value
            def has_more(count: Int, maxc: Int) = // Boolean
                count <= maxc 
            def incr {
                kount = kount + 1
            }
            while (has_more(kount: Int, maxc: Int)) {
                println(kount.toString)
                incr
            }
        }
        def main(args: Array[String]) {
            counter(0,10)
        }
    }

Procedural Paradigm (3)

        def counter(count: Int, maxc: Int) {
            var kount = count  // cannot change parameter value
            def has_more(count: Int, maxc: Int) = // Boolean
                count <= maxc 
            def incr {
                kount = kount + 1
            }
            while (has_more(kount: Int, maxc: Int)) {
                println(kount.toString)
                incr
            }
        }

Procedural Paradigm (4)

    def counter(count: Int, maxc: Int) {
        var kount = count  // cannot change parameter value
        def has_more(count: Int, maxc: Int) = // Boolean
            count <= maxc 
        def incr {
            kount = kount + 1
        }
        while (has_more(kount: Int, maxc: Int)) {
            println(kount.toString)
            incr
        }
    }

Procedural Paradigm (5)

    def counter(count: Int, maxc: Int) {
        var kount = count  // cannot change parameter value
        def has_more(count: Int, maxc: Int) = // Boolean
            count <= maxc 
        def incr {
            kount = kount + 1
        }
        while (has_more(kount: Int, maxc: Int)) {
            println(kount.toString)
            incr
        }
    }

Procedural Paradigm (6)

Primarily procedural languages:

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

Modular Paradigm (1)

Modular Paradigm (2)

Use Scala object for module here

    object CountingMod {
        var count =  0   // public, using type inference 
        var maxc  = 10   // declaration & setter/getter better practices 
        private def has_more(count: Int, maxc: Int): Boolean = 
            count <= maxc 
        private def incr {
            count = count + 1
        } 
        def counter {
            while (has_more(count,maxc)) {
                println(count.toString)
                incr
            }
        }
    }

Modular Paradigm (3)

  1. Defines 3 module-level methods: has_more, incr, counter, first 2 private

  2. Defines 2 module-level (object) variables: count, maxc — both part of public interface here

  3. Initializes variables: count, maxc

  4. Gives lexical scope in module to variables & functions

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

    • count, maxc visible in incr, counter

Modular Paradigm (4)

    object CountingModTest {
        def main(args: Array[String]) {
            CountingMod.counter
            println("[1..20]") 
            CountingMod.count =  1
            CountingMod.maxc  = 20
            CountingMod.counter
        }
    }

Modular Paradigm (5)

    // Alternative module defining public interface with trait
    trait CountingIF { 
        def setStart(start: Int) // setters/getters
        def getStart: Int        // Should use better Scala syntax
        def setStop(stop: Int)
        def getStop: Int
        def has_more(count: Int,maxc: Int): Boolean
        def incr 
        def counter
    }

Modular Paradigm (6)

    object CountingMod2 extends CountingIF { // Impl. 1
        private var count =  0 
        private var maxc  = 10
        def setStart(start: Int) { count = start }
        def getStart: Int = count
        def setStop(stop: Int) { maxc = stop }
        def getStop: Int = maxc
        def has_more(c: Int, m: Int) = c <= m
        def incr { count = count + 1 }
        def counter {
            while (has_more(count,maxc)) {
                println(count.toString)
                incr
            }
        }
    }

Modular Paradigm (7)

    object CountingMod2a extends CountingIF { // Impl. 2
        private var count =  0
        private var maxc  = 10
        def setStart(start: Int) {
            count = start
        }
        def getStart: Int = count
        def setStop(stop: Int) { maxc = stop }
        def getStop: Int = maxc
        def has_more(c: Int, m: Int) = 
            c != 0 && Math.abs(c) <= Math.abs(m)
        def incr { count = count * 2 }
        def counter {
            while (has_more(count,maxc)) {
                println(count.toString)
                incr
            }
        }
    }

Modular Paradigm (8)

    object CountingModTest2 { // Main module
        def main(args: Array[String]) {
            CountingMod2.counter
            println("[1..20]")
            CountingMod2a.setStart(1)
            CountingMod2a.setStop(20)
            CountingMod2a.counter
        }
    }

Modular Paradigm (9)

Other Programming Paradigms

Key Ideas

Source Code