![]() |
CS 334
|
Example
- val p = ref 17 val p = ref 17 : int refCan get at value of reference by writing !p
- !p + 3; val 20 : intAlso have assignment operator ":="
- p := !p + 1; () : unit - !p; val 18 : intOther imperative commands:
(E1; E2; ...; En) - evaluate all expressions (for their side-effects), returning value of En
while E1 do E2 - evaluates E2 repeatedly until E1 is false (result of while always has type unit)
Writing Pascal programs in ML:
fun decrement(counter : int ref) = counter := !counter - 1; fun fact(n) = let val counter = ref n; val total = ref 1; in while !counter > 1 do (total := !total * !counter ; decrement counter); !total end;There are restrictions on the types of references - e.g., can't have references to polymorphic objects (e.g., nil or polymorphic fcns). See discussion of non-expansive expressions in section 5.3.1. Essentially, only function definitions (or tuples of them) can have polymorphic type. Results of function applications or values of references can never be polymorphic.
Passing around fcns can be expensive, local vbles must be retained for later execution. Therefore must allocate from heap rather than stack.
Recursion typically uses lot more space than iterative algorithms
New compilers detect "tail recursion" and transform to iteration.
Lack of destructive updating. If structure is changed, may have to make
an entirely new copy (though minimize through sharing).
Results in generating lot of garbage so need garbage collection to go on in
background.
"Listful style" - easy to write inefficient programs that pass lists around when single element would be sufficient (though optimization may reduce).
If lazy evaluation need to check whether parameter has been evaluated
- can be quite expensive to support.
Need efficient method to do call by name -
carry around instructions on how to
evaluate parameter - don't evaluate until necessary.
Lazy would be slower.
What would happen if we designed an alternative architecture based on functional programming languages?
Because values cannot be updated, result not dependent on order of evaluation.
Therefore don't need explicit synchronization constructs.
If in distributed environment can make copies w/ no danger of copies becoming inconsistent.
If evaluate f(g(x),h(x)) can evaluate g(x) and h(x) simultaneously (w/ eager evaluation).
Two sorts of parallel architectures: data-driven and demand-driven.
Idea is programmer need not put parallel constructs into program and same program will run on single processor and multi-processor architectures.
Not quite there yet. Current efforts require hints from programmer to allocate parts of computation to different processors.
Referential transparency supports reasoning about programs and execution on highly parallel architectures.
While lose assignment and control/sequencing commands, gain power to write own higher-order control structures (like listify, while, etc.)
Some cost in efficiency, but gains in programmer productivity since fewer details to worry about (higher-level language) and easier to reason about.
Languages like ML, Miranda, Haskell, Hope, etc. support implicit polymorphism resulting in greater reuse of code.
ML features not discussed:
ML currently being used to produce large systems. Language of choice in programming language research and implementation at CMU, Princeton, Williams, etc.
Computational biology: Human genome project at U. Pennsylvania
Lots of research into extensions. ML 2000 report.
Addition of object-oriented features?
First used in ALGOL 60 Report - formal description
Generative description of language.
Language is set of strings. (E.g. all legal ALGOL 60 programs)
<expression> ::= <term> | <expression> <addop> <term> <term> ::= <factor> | <term> <multop> <factor> <factor> ::= <identifier> | <literal> | (<expression>) <identifier> ::= a | b | c | d <literal> ::= <digit> | <digit> <literal> <digit> ::= 0 | 1 | 2 | ... | 9 <addop> ::= + | - | or <multop> ::= * | / | div | mod | and
Generates: a + b * c + b - parse tree
Grammar gives precedence and which direction op's associate
Extended BNF handy:
item enclosed in square brackets is optional
<conditional> ::= if <expression> then <statement> [ else <statement> ]item enclosed in curly brackets means zero or more occurrences
<literal>::= <digit> { <digit> }
Syntax diagrams - alternative to BNF,
Syntax diagrams are never
recursive, use "loops" instead.
<statement> ::= <unconditional> | <conditional>How do you parse:<unconditional> ::= <assignment> | <for loop> |
"{" { <statement> } "}"
<conditional> ::= if (<expression>) <statement> |
if (<expression>) <statement> else <statement>
if (exp1) if (exp2) stat1; else stat2;
Could be
if (exp1) { if (exp2) stat1; else stat2; }or
if (exp1) { if (exp2) stat1; } else stat2;
Ambiguous
Pascal, C, and Java rule: else attached to nearest then
To get second form, include "{,}".
MODULA-2 and ALGOL 68 require "end" to terminate conditional:
Why isn't it a problem in ML?
Ambiguity in general is undecidable
Chomsky developed mathematical theory of programming languages:
Not all aspects of programming language syntax are context-free.
Back to:
kim@cs.williams.edu