from concurrent constraint programming to concurrent functional programming with transients summer...

73
From Concurrent Constraint Programming to Concurrent Functional Programming with Transients Summer School of Constraints in Computational Logics Gif-sur-Yvette, France, 5-8 September 1999 Gert Smolka Universität des Saarlandes Saarbrücken, Germany

Upload: garey-pearson

Post on 02-Jan-2016

248 views

Category:

Documents


0 download

TRANSCRIPT

FromConcurrent Constraint Programming

to Concurrent Functional Programming

with Transients

Summer School of Constraints in Computational Logics Gif-sur-Yvette, France, 5-8 September 1999

Gert SmolkaUniversität des Saarlandes

Saarbrücken, Germany

2

What can LP and CCP contribute to the design of high-level, general-purpose

programming languages?

Background:

Development of Oz and Mozart (1991-1998)

LP : Logic Programming

CCP : Concurrent Constraint Programming

3

Overview

1. Review and critique of CCP

2. Concurrent functional programming with transients

4

History of CCP

• Automated Theorem Proving• Logic Programming (1974)• Constraint Logic Programming (1982)• Concurrent Logic Programming (1983)• Concurrent Constraint Programming (1987)

5

Logic Programming

• Horn clauses as programming language (Kowalski 1974)• Simple, expressive, new• Operational semantics = declarative semantics• Don't know choice, logic variables, unification• Prolog (Colmerauer 1972)• Processing of natural language

6

Constraint Logic Programming

• Solve combinatorial problems• Built-in numbers• Constraint solving as generalization of unification• Constraint propagation• Prolog II (Colmerauer 1982), CHIP (1987)• CLP(X) (Jaffer/Lassez 1987)

• ILOG Solver (C++ Library)• Constraint programming as a research discipline

7

Concurrent Logic Programming

• Program operating systems (Jap. 5th Gen. Project)• Exploit massively parallel hardware• Concurrent Prolog (Shapiro 1983), GHC (Ueda 1986)

8

Concurrent Constraint Programming

• Unified theory – ALPS (Maher 1987)– CC (Saraswat 1989)– OPM (Smolka 1995)

• Unified programming languages– AKL (1992)– Oz (1994, 1997)

9

Constraints

• Set of values Value• Set of variables Var• Assignments are functions Var Value• Abstract constraint is a set of assignments• Concrete constraint is a syntactic object (e.g., x+y=z)

that denotes an abstract constraint• Constraint represents (possibly partial) information

about the values of variables• Constraint system: Values and concrete constraints

closed under intersection and existential quantification

10

Constraint Store

• Holds abstract constraint (satisfiable)• Operations

– New variable (i.e., unconstrained)– Tell constraint (success, failure)– Ask constraint (entailed, disentailed, undetermined)– Show information about variables

11

Computational Setup

• Transition system

C1 C2 C3 C4 . . .

• Configuration

(state of store, states of agents)• Termination with success or failure• Don't know choices

Actor . . . Actor

Constraint Store

12

Programs

• Actor statements a ::= new x in a

tell c

if c1a1 [] c2a2

a1 | a2

a1 + a2

p(x)

• Procedure definitions

p(x) :- a

13

CCP is Good Research Idealization

• Models essentials of constraint and concurrent LP• Valuable background for Constraint Programming• Potential for massive parallelism

14

From CC to OPM

• Constraint store unrealistic for numeric values– Propagators

• Communication based on logic streams unrealistic– State

• Primitive procedures– First-class procedures

• Don't know choices not encapsulated– Spaces

CC : Concurrent Constraints [Saraswat 89]OPM : Oz Programming Model [Smolka 95]

15

Still, CCP is not well-suited as a basis for

programming languagedue to

lack of explicit functional structure

• Input -> Output (monotone side effects)• Safe binding of variables (unsave tell)• Static typing with parametric

and subtype polymorphism

16

Programming Models versus Programming Languages

• A programming model is a research idealizationthat has nice properties (science)– functional programming, strict or lazy– logic programming, constraint or concurrent– concurrent calculi based on channels

• A programming language is a tool that should support several programming models (engineering)

Concurrent Functional Programmingwith Transients

18

ML + Threads + Transients

• ML (SML or Objective Caml)– Functional programming language, eager– Types and modules– State and exceptions

• SML has formal definition• Objective Caml has

– objects and classes– threads and channels

19

Plan

1. FP + concurrency

2. Futures

3. Promises

4. Streams

5. Channels

20

Threads, Processes

Thread . . . Thread

Resources Process

External Resources

21

Values, Resources, Addresses

• Values are stateless entities– numbers, tuples, procedures, ...– can be replicated

• Resources are stateful entities– cells, channels, threads, file systems, ...– cannot be replicated (their states can)

• Addresses are values that identify resources

22

Pointers (Simple Resource)

type 'a ref

val ref : 'a -> 'a ref

val deref : 'a ref -> 'a

val assign : 'a ref * 'a -> unit

val exchange : 'a ref * 'a -> 'a

NB: exchange is atomic

23

Channels (Synchronizing Resource)

type 'a channel

val channel : unit -> 'a channel

val put : 'a channel * 'a -> unit

val get : 'a channel -> 'a

• Channel is queue with synchronization• Get operation blocks if channel is empty• Theoretically well-investigated: CCS, Pi-calculus

24

Threads (Active Resource)

type thread

val thread : (unit -> unit) -> thread

val suspend : thread -> unit

val resume : thread -> unit

val kill : thread -> unit

25

Concurrency Issues

• Threads perform atomic computation steps• Interleaving semantics• Operations on resources are atomic• Operations on resources may block• Nondeterminism (e.g., concurrent puts)• Fairness

– advance threads that can advance– serve competing gets fairly

26

Plan

1. FP + concurrency

2. Futures (Multilisp, Halstead 1985)

3. Promises

4. Streams

5. Channels

27

Concurrent Evaluation with Futures

conc exp

• Spawns new thread that evaluates exp• Returns future that acts a placeholder for result of exp• Operations block when applied to futures,

resume automatically• Provides for parallel execution and latency tolerance

28

Don't need new Syntax

conc : (unit -> 'a) -> 'a

29

Latency Tolerance with Futures

Client Server

request

answer

conc remote_procedure_call

30

Concurrent Evaluation with Futures

• Can evaluate e1 and e2 in parallel• Can start application before value of e2 is

obtained• With futures, sequential code can be run

concurrently with automatic "latest possible time" synchronization

let val x = conc e2

in e1 x ende1 e2

31

Explicit Synchronization

1. Evaluate e1 and e2 concurrently

2. Evaluate e3 after evaluation of e1 and e2 has finished

case

(conc(e1;()), conc(e2;()))

of

((),()) then e3

32

By-need Evaluation with Futures

byneed exp

• Same as conc exp, but slightly different control• Thread evaluating exp only starts once future is needed• Provides for lazy functional programming

33

Lazy Functions

fn x => exp

fn x => byneed exp

34

0::1::2::3::4::5:: ...

future1::future1::2::future1::2::3::future1::2::3::4::future

Lazy Stream of Natural Numbers

35

fun gen(n) = byneed n::gen(n+1)

val natStream = gen(0)

Lazy Stream of Natural Numbers

36

Operational Semantics

• env, exp value pure functional , env, exp value, ' plus state , threads threads, ' plus threads , , threads threads, ', ' plus futures

37

Futures Formaly

• Assume set of futures (addresses of resources)• Closed values: values of functional language• Values = closed values + open values Future fin Value

• Open values can be updated wrt

38

Plan

1. FP + concurrency

2. Futures

3. Promises (typed substitute for logic variables)

4. Streams

5. Channels

39

Promises

type 'a promise

val promise : unit -> 'a promise

val fulfill : 'a promise * 'a -> unit

val future : 'a promise -> 'a

• Promise is a single assignment pointer• fulfill binds promise to value• future returns value of promise or its future• fulfill raises exception if promise is already bound

40

Concurrent Evaluation with Promises

conc : (unit -> 'a) -> 'a

fun conc f = let val p = promise() in thread fulfill(p,f()); future p end

41

Recursion with Promises

val rec x = 1::x

let val p = promise() val x = 1::future pin fulfill(p,x); xend

42

Difference Lists with Promises

type 'a dlist

val dlist : unit -> 'a dlist

val cons : 'a * 'a dlist -> 'a dlist

val append : 'a dlist * 'a dlist -> 'a dlist

val close : 'a dlist * 'a list -> 'a list

val export : 'a dlist -> 'a list

• All operations are constant time• Exactly one append or close per dlist

43

type 'a dlist = 'a list * 'a list promise

fun dlist() = let val p = promise() in (future p, p) end

fun cons(x,(xs,p)) = (x::xs,p)

fun append((xs,p),(ys,p')) = (fulfill(p,ys); (xs,p'))

fun close((xs,p),ys) = (fulfill(p,ys); xs)

fun export(xs,_) = xs

44

Promise Types are Invariant wrt Subtyping

fulfill: 'a promise * 'b -> unit ('b <:'a)

future : 'a promise -> 'b ('a <:'b)

• Typing of promises is exactly as typing of references• Must not have polymorphic promises (comes for free

due to value restriction on polymorphism and generator function)

45

Logic Variables are Inconsistent with Subtyping

val lvar : unit -> 'a

val bind : 'a * 'a -> unit

let val x:colorPoint = lvar()in bind(x:point, p:point); printColorPoint(x:colorPoint)end

46

Futures and Exceptions

• byneed exp• Futures have 3 states: undetermined, succeeded,failed• Failed future is associated with an exception• Access to failed future raises associated exception• If exp of byneed exp fails with an exception exn, the

by-need future is failed with exn

• Design trade-off between – implicit blocking– explicit error

47

Failed Promises

val fail : 'a promise * exn -> unit

• Failing a promise includes failing its associated future• Application of fail to a fulfilled or already failed

promise raises an exception

48

Plan

1. FP + concurrency

2. Futures

3. Promises

4. Streams (concurrent logic programming)

5. Channels

49

Streams

A stream is a possibly partial list

x1 :: x2 :: x3 :: future

pluszs

ys

xs

50

Concurrent Stream Transformer

fun newPlus(xs,ys) =

let

val p = promise()

in

thread plus(xs,ys,p);

future p

end

51

plus : 'a list * 'a list * 'a promise -> unit

fun plus(x::xr, y::yr, p) =

plus(xr, yr, next(p,x+y))

52

next : 'a promise * 'a -> 'a promise

fun next(p,x) = let val p' = promise() in fulfill(p, x::(future p')); p' end

53

Nondeterministic Choice

mergezs

ys

xs

54

Two possibilities

1. Pointers with exchange– Mailbox feeding output stream– One transfer loop for every input stream

2. Additional primitives for futures– Don't need pointers– Similar to how it is done in Concurrent Logic

Programming

55

Primitives for Nondeterministic Choice

val isFuture : 'a -> bool

val waitOne : 'a * 'b -> 'a

waitOne blocks until at least one argumentis a non-future

56

fun merge(xs, ys, p) =

if isFuture(waitOne(xs,ys))

then merge(xs, tl ys, next(p,hd ys))

else merge(ys, tl xs, next(p,hd xs))

57

Time-outs

timeout: ’a * int -> ’a option

alarm: int -> unit

fun timeout(x, t) = if isfuture(waitOne(x, alarm t)) then NONE else SOME x

58

Plan

1. FP + concurrency

2. Futures

3. Promises

4. Streams

5. Channels

NB: Fair channels can be done with blocking promises

59

Channels

type 'a channel

val channel : unit -> 'a channel

val put : 'a channel * 'a -> unit

val get : 'a channel -> 'a

• Channel is queue with synchronization• Get operation blocks if channel is empty• Blocked threads are served fairly (FIFO)

60

Channels

put

Stream

get

dispenser + mailbox

61

Mailboxes

type 'a mailbox

val mailbox : unit -> 'a mailbox * 'a list

val put : 'a mailbox * 'a -> unit

Provide for many-to-many communication

62

x1 :: x2 :: x3 :: future

promise

pointer

63

x1 :: x2 :: x3 :: future

promise promise

pointer

64

x1 :: x2 :: x3 :: x4 :: future

promise promise

pointer

65

type 'a mailbox = 'a list promise ref

fun mailbox() = let val p = promise() in (ref p, future p) end

fun put(r,x) = let val p = promise() in fulfill(exchange(r,p), x::future p) end

66

Dispensers

type 'a dispenser

val dispenser : 'a list -> 'a dispenser

val get : 'a dispenser -> 'a

• Get operation blocks if next message is not yet available

• Blocked threads are served fairly (FIFO)

67

pointer

stream

68

pointer

stream future

promise

thread1

69

pointer

stream future future

promise promise

thread1 thread2

70

type 'a dispenser = 'a list ref

fun dispenser xs = ref xs

fun get r = let val p = promise() val x::xr = exchange(r, future p) in fulfill(p,xr); x end

71

Summary

• ML + threads + transients• Transients

– Futures with eager provider– Futures with lazy provider– Futures with promise as provider

• Provides for– Automatic "latest possible time" synchronization of

sequential code– Lazy evaluation– Top-down construction of values (e.g., streams)– Concurrent data structures (e.g., channels)

72

Performance Costs of Futures

• Not observable for emulating implementation (Mozart, OCaml)

• Low for compiling implementation provided static analysis is employed

• Futures are omnipresent• Analogous to lazy closures

73

Learning More

• Gert Smolka, The Oz Programming Model. Springer LNCS 1000, pages 324-343, 1995

• Gert Smolka, Concurrent Constraint Programming Based on Functional Programming. ETAPS'98, Springer LNCS, 1998

• Papers referred to in the above papers• The Mozart System. www.mozart-oz.org