CS 3304 Comparative Languages

Slides:



Advertisements
Similar presentations
1 Copyright © 1998 by Addison Wesley Longman, Inc. Chapter 14 Functional Programming Languages - The design of the imperative languages is based directly.
Advertisements

1 Scheme and Functional Programming Aaron Bloomfield CS 415 Fall 2005.
Recap 1.Programmer enters expression 2.ML checks if expression is “well-typed” Using a precise set of rules, ML tries to find a unique type for the expression.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
Lambda Calculus and Lisp PZ03J. Lambda Calculus The lambda calculus is a model for functional programming like Turing machines are models for imperative.
CS 355 – PROGRAMMING LANGUAGES Dr. X. Apply-to-all A functional form that takes a single function as a parameter and yields a list of values obtained.
Chapter 15 Other Functional Languages. Copyright © 2007 Addison-Wesley. All rights reserved. Functional Languages Scheme and LISP have a simple syntax.
Chapter 15 Functional Programming Languages. Copyright © 2007 Addison-Wesley. All rights reserved. 1–2 Introduction Design of imperative languages is.
Dr. Muhammed Al-Mulhem ICS An Introduction to Functional Programming.
1 Chapter 5: Names, Bindings and Scopes Lionel Williams Jr. and Victoria Yan CSci 210, Advanced Software Paradigms September 26, 2010.
Chapter 10 :: Functional Languages
Copyright © 2009 Elsevier Chapter 10 :: Functional Languages Programming Language Pragmatics Michael L. Scott.
Functional Programing Referencing material from Programming Language Pragmatics – Third Edition – by Michael L. Scott Andy Balaam (Youtube.com/user/ajbalaam)
ISBN Chapter 15 Functional Programming Languages.
CSE S. Tanimoto Lambda Calculus 1 Lambda Calculus What is the simplest functional language that is still Turing complete? Where do functional languages.
© Kenneth C. Louden, Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden.
1 COMP313A Functional Programming (1). 2 Main Differences with Imperative Languages Say more about what is computed as opposed to how Pure functional.
CSC 580 – Theory of Programming Languages, Spring, 2009 Week 9: Functional Languages ML and Haskell, Dr. Dale E. Parson.
1 Compiler Construction (CS-636) Muhammad Bilal Bashir UIIT, Rawalpindi.
Functional Programming With examples in F#. Pure Functional Programming Functional programming involves evaluating expressions rather than executing commands.
© Kenneth C. Louden, Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden.
1-1 An Introduction to Functional Programming Sept
1 Programming Languages (CS 550) Lecture 2 Summary Mini Language Interpreter Jeremy R. Johnson.
1 FP Foundations, Scheme In Text: Chapter Chapter 14: FP Foundations, Scheme Mathematical Functions Def: A mathematical function is a mapping of.
Copyright © 2009 Elsevier Chapter 10 :: Functional Languages Programming Language Pragmatics Michael L. Scott.
Functional Programming
CS314 – Section 5 Recitation 9
Functional Programming
Functional Programming Languages
Functional Programming
Functional Programming
CS 3304 Comparative Languages
Unit – 3 :LAMBDA CALCULUS AND FUNCTIONAL PROGRAMMING
Edited by Original material by Eric Grimson
PROGRAMMING LANGUAGES
Chapter 11 :: Functional Languages
CS 326 Programming Languages, Concepts and Implementation
Introduction to Parsing (adapted from CS 164 at Berkeley)
6.001 SICP Variations on a Scheme
CS 326 Programming Languages, Concepts and Implementation
Representation, Syntax, Paradigms, Types
September 4, 1997 Programming Languages (CS 550) Lecture 6 Summary Operational Semantics of Scheme using Substitution Jeremy R. Johnson TexPoint fonts.
Closures and Streams cs784(Prasad) L11Clos
Important Concepts from Clojure
Important Concepts from Clojure
Mini Language Interpreter Programming Languages (CS 550)
Control Flow Chapter 6.
Programming Languages and Compilers (CS 421)
FP Foundations, Scheme In Text: Chapter 14.
Representation, Syntax, Paradigms, Types
Dynamic Scoping Lazy Evaluation
Distributed System Gang Wu Spring,2018.
Announcements Quiz 6 HW7 due Tuesday, October 30
Representation, Syntax, Paradigms, Types
6.001 SICP Further Variations on a Scheme
Delayed Evaluation Special forms in Scheme (e.g., if and cond) do not use applicative order evaluation Only one of two or more expressions is actually.
Streams, Delayed Evaluation and a Normal Order Interpreter
Lecture 12: Message passing The Environment Model
6.001 SICP Variations on a Scheme
L Calculus.
Representation, Syntax, Paradigms, Types
Important Concepts from Clojure
Java Programming Language
6.001 SICP Interpretation Parts of an interpreter
CSE S. Tanimoto Lambda Calculus
Functional Programming and Haskell
Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator
Chapter 15 Functional Programming 6/1/2019.
Functional Programming and Haskell
Presentation transcript:

CS 3304 Comparative Languages Lecture 19: Functional Languages - Perspective 27 March 2012

Evaluation Order Revisited Applicative order - evaluate function arguments before passing them to a function: Scheme: functions use applicative order defined with lambda. What is usually done in imperative languages. Usually faster. Scheme use applicative order in most cases. Normal order - pass function arguments unevaluated: Scheme: special forms (hygienic macros) use normal order defined with syntax-rules. Arises in the macros and call-by-name parameters of imperative languages. Like call-by-name: don't evaluate argument until you need it. Sometimes faster. Terminates if anything will (Church-Rosser theorem).

Example Function: (define double (lambda (x) (+ x x))) Applicative order: (double (* 3 4)) ⇒ (double 12) ⇒ (+ 12 12) ⇒ 24 Normal order: (double (* 3 4)) ⇒ (+ (* 3 4) (* 3 4)) ⇒ (+ 12 (* 3 4)) ⇒ (+ 12 12) ⇒ 24

Special Forms Arguments to special forms (such as lambda) are passed unevaluated. Each special form is free to choose internally when (and if) to evaluate its parameters. Expression types in Scheme - special forms and functions: Primitive: built into the language implementation. Derived: defined in terms of primitive expression types. lambda: used to create derived functions that can be bound to names with let. syntax-rules: used to create derived special forms that can be bound to names with define-syntax and let-syntax. Derived special forms are known as macros in Scheme – hygienic: lexically scoped, integrated into the language’s semantics, and immune from the problems of mistaken grouping an variable capture. Scheme macros are Turing complete.

Strictness A (side-effect-free) function is said to be strict if it is undefined (fails to terminate, or encounters an error) when any of its arguments is undefined. It can safely evaluate all its argument, so its result will not depend on evaluation order. A strict language requires all arguments to be well-defined, so applicative order can be used: ML and Scheme (with the exception of macros). A non-strict language does not require all arguments to be well-defined; it requires normal-order evaluation: Miranda and Haskell.

Lazy Evaluation Lazy evaluation gives the best of both worlds: the advantage of normal-order evaluation while running within a constant factor of the speed of applicative-order evaluation. Particularly useful for “infinite” data structures. Scheme: available through explicit use of delay and force: delay creates a “promise”. But not good in the presence of side effects. If an argument contains a reference to a variable that may be modified by an assignment, then the value of the argument will depend on whether it is evaluated before or after the assignment. If the argument contains an assignment, values elsewhere in the program may depend on when evaluation occurs. Scheme requires that every use of delay-ed expression be enclosed in force.

Lazy Evaluation Example (define f (lambda () (let ((done #f) (memo ’()) (code (lambda () (* 3 4)))) (if done memo (begin (set! memo (code)) memo))))) … (double (f)) ⇒ (+ (f) (f)) ⇒ (+ 12 (f)) ⇒ (+ 12 12) ⇒ 24

I/O Streams Traditional I/O is a major source of side effects: Scheme: functions read and display. Model input and output as streams: unbounded-length lists whose elements are generated lazily. If we model input and output streams, then: (define output (my_prog input)) When input value is needed, my_prog forces evaluation of the car of input and passes the cdr on to the rest of the program. Successfully encapsulate the imperative nature of interaction at terminal. Don’t work well for graphics or random access to files.

Monads A more general concept (from category theory): Ability to carry a hidden, structured value of arbitrary complexity from one action to the next. The pseudorandom number generator example (p. 526): Passing the state to the function and having it return new state along with the random number. Monads provide a more general solution to the problem of threading mutable state through a functional program. In Haskell IO monad serves as the central repository for imperative language features (syntactic sugar): Additional nomads support partial functions and various container classes. Coupled with lazy evaluation provides a natural foundation for backtracking search, nodeterminism, and the functional equivalent of iterators.

Higher-Order Functions Take a function as argument, or return a function as a result. Great for building things. Map: takes as argument a function and a sequence of lists: (map * '(2 4 6) '(3 5 7)) One of the most common uses of higher order functions is to build new functions from existing ones: (define fold (lambda (f i l) (if (null? l) i (f (car l) (fold f i (cdr l)))))) (define total (lambda (l) (fold + 0 l))) (define total-all (lambda (l) (map total l)))

Implementing Higher-Order Functions Whey we don’t use higher-order function in imperative programming languages? Much of the power of the first-class functions depends on the ability to create new functions on the fly - we need a function constructor: a significant departure from the syntax and semantics of traditional imperative languages. The ability to specify functions as return values, or to store them as variables requires: Eliminate function nesting: erodes the ability of programs to create functions with desired behaviors on the fly; or Give local variables unlimited extent: increases the cost of storage management.

Currying Currying (after Haskell Curry): replace multiargument function with a function that takes a single argument and returns a function that epect the remaining elements: (define curried-plus (lambda (a) (lambda (b) (+ a b)))) (plus 3 4) ⇒ 7 (map (curried-plus 3) ‘(1 2 3)) ⇒ (4 5 6) ML, Miranda, and Haskell have especially nice syntax for curried functions. In ML: fun plus (a, b) : int = a + b; ==> val plus = fn : int * int -> int fun curried_plus a = fn b : int => a + b; ==> val curried_plus = fn : int -> int -> int curried_plus 3; ==> val it = fn : int -> int fun curried_plus a b : int = a + b; ==> val curried_plus = fn : int -> int -> int

Theoretical Foundations: Functions A function is a single-valued mapping: it associates every element in one set (the domain) with (at most) one element in another set (the range): sqrt: R ⟶ R If a function provides a mapping for every element of the domain, the function is said to be total. Otherwise, it is said to be partial. It is often useful to characterize functions as sets or, more precisely, as subsets of the Cartesian product of the domain and the range. One of the limitations of the function-as-set notation is that it is nonconstructive: it doesn’t tell us how to compute the value of a function at a given point (i.e., on a given input).

Theoretical Foundations: Lambda Calculus Church designed the lambda calculus to address the nonconstructive limitation of function-as-set. In its pure form, lambda calculus represents everything as a function: Church and Rosser theorem: the simplest forms are unique and that if any evaluation order will terminate, normal order will. A lambda expression can be defined recursively as: A name; A lambda abstraction consisting of the letter λ, a name, a dot, and a lambda expression; A function application consisting of two adjacent lambda expressions; A parenthesized lambda expression. To accommodate arithmetic, we will extend this definition to allow numeric literals. When two expressions appear adjacent to one another, the first is interpreted as a function to be applied to the second.

Naturally Imperative Idioms There are common programming idioms in which the canonical side effect (assignment) plays a central role, such as I/O and trivial update problem idioms: Initialization of complex structures: lists are easy to build from old lists but not other data structures, such as multidimensional arrays. Summarization: the natural way to count occurrences of various item in large data sets is using a dictionary data structure that is repeatedly updated. In-place mutation: when dealing with large data sets, values should be updated in place rather than copying to a new list or similar. Solution: a combination of convenient notation (accessing arbitrary elements of a complex structure) and an implementation that can determine when the old version of the structure will never be used gain and can be updated in place.

Perspective: Advantages Lack of side effects makes programs easier to understand. Lack of explicit evaluation order (in some languages) offers possibility of parallel evaluation (e.g. MultiLisp). Lack of side effects and explicit evaluation order simplifies some things for a compiler (provided you don't blow it in other ways). Programs are often surprisingly short. Language can be extremely small and yet powerful.

Perspective: Problems Difficult (but not impossible!) to implement efficiently on von Neumann machines: Lots of copying of data through parameters. (Apparent) need to create a whole new array in order to change one element. Heavy use of pointers (space/time and locality problem). Frequent procedure calls. Heavy space use for recursion. Requires garbage collection. Requires a different mode of thinking by the programmer. Difficult to integrate I/O into purely functional model.

Summary A functional program computes principally through substitution of parameters into functions. The underlying formal model for functional languages is the lambda calculus. Many functional languages extend the lambda calculus with additional features, including assignment, I/O, and iteration. Lists feature prominently in most functional languages.