This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Little LanguagesLittle Languagesfor Big Applicationsfor Big Applications
Paul HudakPaul HudakDepartment of Computer ScienceDepartment of Computer Science
• At Yale: John Peterson, Walid Taha, Henrik Nilsson, Antony Courtney, Zhanyong Wan
• Conal Elliott, Micro$oft Research• Greg Hager, Johns Hopkins University• Alastair Reid, University of Utah
Is “Higher Level” Is “Higher Level” Better?Better?
• A programming language can be viewed as an interface to an abstract machine.
• When is one general-purpose language higher-level than another?
• Assembly language is just the right abstraction for a CPU.
• Why do some languages better match some applications than others?
We Need Domain We Need Domain SpecificitySpecificity
• A domain-specific language (or DSL) is a language that precisely captures a domain semantics; no more, and no less.
• We also need domain specific:– specifications (starting point!)– optimizations and transformations– software tools– type systems, aspects, constraints, etc.
• Programs in the target domain are:– more concise– quicker to write
– easier to maintain
– easier to reason about
– can often be written by non-programmers
Advantages of DSL Advantages of DSL ApproachApproach
Contribute to higherprogrammer productivity
Dominant cost in large SW systems
Verification, transform- ation, optimization
Helps bridge gap betweendeveloper and user
These are the same arguments in favor of any high-level language. But in addition:
Why Study DSL’s?Why Study DSL’s?• Ok, so perhaps DSL’s are useful.• But why should programming language
researchers be interested in DSL’s?– To have an impact on the real world.– The chances of a general purpose language
succeeding are slim, no matter how good it is.– DSL design and implementation is a source of
new and interesting problems.– It is also fun!
• In the remainder of the talk I will concentrate on the latter two points.
A Case Study: FRPA Case Study: FRP• Fran is a DSL for graphics and animation.• Frob is a DSL for robotics.• FranTk is a DSL for graphical user interfaces.• FRP (functional reactive programming) is
the essence of Fran, Frob, and FranTk:– Fran = FRP + graphics engine + library– Frob = FRP + robot controller + library– FranTk = FRP + Tk substrate + library
• FRP has two key abstractions:– Continuous time-varying behaviors.– Discrete streams of events.
• HaskellScript for the WWW (Utrecht)• Scripting COM objects (Utrecht, Microsoft)• Hardware Description (OGI, Chalmers)• Parsing/pretty printing (Utrecht, Chalmers)• GUI’s (FranTK, etc.)
At Yale:
Elsewhere:
A Typical Fran A Typical Fran ExpressionExpression
1 `until` time>2 -=> time+1
Behavior BehaviorPredicate event
Infix operator Infix operator
This is equivalent to:
(until 1 ((-=>)((>) time 2)((+) time 1)))
But, what are behaviors and events?
Fran’s BehaviorsFran’s BehaviorsHaskell’s type classes conveniently describe behaviors: newtype Behavior a = Beh (Time -> a) instance Num (Behavior a) where Beh f + Beh g = Beh (\t -> f t + g t) fromInteger x = Beh (\t -> x)
color = red `until` lbp ==> blue `until` lbp ==> color
which would not terminate under a call-by-value interpretation.
Lazy evaluation is also central to our stream-based implementation, thus emulating “demand-driven” computation.
The Semantics of FranThe Semantics of Fran• Denotational semantics [Elliott,Hudak,ICFP98]
– at [[b]] t : instantaneous value of behavior b at time t.– occ [[e]] t : presence of event e at time t.– Domain (cpo) of time T, with partial elements >t that
denote “a time that is at least t”.• Stream-based operational semantics [Hudak2000
and Wan,Hudak,PLDI2000]– Streams represent behaviors and events.– Compositional semantics via stream transformers.– Leads naturally to concrete implementation.
Theorem: In the limit, as sample time goes to zero,the stream-based semantics is faithful tothe denotational semantics [PLDI2000].
From Semantics to From Semantics to ImplementationImplementation
ICFP semantics:
at :: Beh a -> Time -> aocc :: Event a -> ((Time,a), Event a)
time :: Beh Timetime `at` t = t
switch :: Beh b -> Event (Beh b) -> Beh b(b `switch` e) `at` t = let ((t0,b0),e0) = occ e in if t<=t0 then b `at` t else (b0 `switch` e0) `at` t
which suggests the implementation:
type Beh a = Time -> atype Event a = [(Time, a)]
b `at` t = b tocc e = (head e, tail e)
User semantics:
at :: Beh a -> (User, Time) -> aocc :: (User, Event a)->((Time,a),User)
time :: Beh Timetime `at` (u,t) = t
switch :: Beh b -> Event(Beh b) ->Beh b(b `switch` e) `at` (u,t) = let ((t0,b0),u0) = occ (u,e) in if t<=t0 then b `at` (u,t) else (b0 `switch` e) `at` (u0,t)
which suggests the implementation:
type Beh a = (User, Time) -> atype Event a = User -> ((Time,a), User)type User = [(Time, UA)]
b `at` (u,t) = b (u,t)occ (u,e) = e u
Time-Ordered SearchTime-Ordered Search• Motivation by analogy:
Consider ordered list L :: [T] and function:inList :: [T] -> T -> Bool
This is quadratic: O(|xs|*|ys|)• Better to order ys first, then do the search:
manyInList xs (y:ys) = let (b,xs’) = inListRem xs yin b : manyInList xs’ ys
This is linear: O(|xs|)
Type-Directed Type-Directed DerivationDerivation
Behaviors:
specification: Beh a = (User, Time) -> auncurry: Beh a = User -> Time -> atime-ordered search: Beh a = User -> [Time] -> [a]unfold User: Beh a = [(UA,Time)] -> [Time] -> [a]unzip User and uncurry: Beh a = [UA] -> [Time] -> [Time]->[a]synchronize: Beh a = [UA] -> [Time] -> [a]
Events:
specification: Ev a = User -> ((Time,a), User)encode non-occurences: Ev a = User -> (Maybe (Time,a), User)decouple aging: Ev a = User -> Maybe (Time,a)time-ordered search: Ev a = User -> [Maybe (Time,a)]unfold User: Ev a = [(UA,Time)] -> [Maybe (Time,a)]unzip User and uncurry: Ev a = [UA] -> [Time] -> [Maybe (Time,a)]synchronize: Ev a = [UA] -> [Time] -> [Maybe a]
Note now: Ev a = Beh (Maybe a)
Advantages of Stream Advantages of Stream DesignDesign
• “User” implicitly “aged;” no User argument to event generators.
• No dynamic adjustments in time; everything is fully synchronized.
• Behaviors can be memoized using a singleton cache.
• Potential for heavy optimization. • Event a = Behavior (Maybe a)
One disadvantage: cannot easily time-transform User.
Faithful Faithful ImplementationsImplementations
• The stream implementation of FRP is an approximation to continuous behaviors.
• But the denotational semantics is exact.• So in what sense is the implementation
faithful to the formal semantics?• Is there any hope for semantics-directed
compilation or transformation/optimization?
Egregious BehaviorsEgregious Behaviors• Consider this behavior:
• This captures Zeno’s Paradox:
and is a natural expression of non-determinism!
time
light off
light onon or off??
1 2
> zeno :: Event ()> zeno = when (lift1 f time) where> f t = if t>2 || t<1 then t<0.5> else f (2*t-2)
More Egregious More Egregious BehaviorBehavior
• Consider this simple behavior:
• This seems innocent enough, but the predicate is true only instantaneously at time = 1. However, a stream-based implementation may miss this event.
• In fact we can show that: A stream-based implementation may miss this event even at the limit of event sampling.
> sharp :: Event ()> sharp = when (time ==* 1)
““Good” BehaviorsGood” Behaviors• Zeno’s paradox represents a problem with the
semantics, and instantaneous events represent a problem with a stream-based implementation.
• Solution: define good behaviors as those that converge to a stable value as the sampling rate increases. Similarly, good events are those whose frequency within a finite period becomes stable as the sampling rate increases.
• Key result: we can show that, with suitable constraints, in the limit, as the sample time decreases to zero, a steam-based implementation is faithful to the denotational semantics.
Lambda in Motion:Lambda in Motion:Controlling Robots with Controlling Robots with HaskellHaskell
Robots with VisionRobots with Vision
MotivationMotivation
• Mobile robot control is hard!• Prototyping is essential: repeated experimentation
required.• Must deal with uncertainty: imprecise sensors,
A Control System for Wall FollowingA Control System for Wall Following
Front Sonar
Side Sonar
Objectives: Maintain a specified distance from wall
Don’t turn too much toward wall
Stop (slowly) when approaching an obstacle ahead.
= limit(max, f - d)= limitsinmax * curr, s - d) - ds/dtlimit(mx,v) = max(-mx,min(v,mx))
s
f
follow f s d = (v,w) where v = limit vmax (f-d) w = limit (vcurr * sin amax) (s-d) - derivative s
Time is Implicit!Notation is nearly identical.Details of clocking are hidden.
Adding ReactivityAdding Reactivity
type Wheels = (SpeedB, AngleB)wfollow :: SonarB -> SonarB -> FloatB -> (WallEnd -> Wheels) -> Wheels wfollow f s d c = follower f s d `untilB` ( predicate (f <= d) -=> Blocked .|. predicate (s >= 2*d) -=> NoWall) ==> c
Wall follower terminates two ways:
-- Blocked in front -- No wall on side
The behaviorThe terminating eventThe continuation of the overall behaviorCapture this pattern in a Monad!
Data WallEnd = Blocked | NoWall
A Task MonadA Task MonadA task couples a behavior with a termination event. In it’s simplest form, we combine a behavior and an event into a task:
mkTask :: (Behavior a, Event b) -> Task a b
Continuous value defined by task
Value returned at end of task
(b1,e1) >> (b2,e2) = (b1 `untilB` e1 -=> b2, e2)
Hide reactivity inside monadic sequencing
Using TasksUsing TaskswallTask f s d = mkTask (wallFollow f s d, predicate (f <= d) -=> Blocked .|. predicate (s >= 2*d) -=> NoWall)
roomFollow f s d = do status <- wallTask f s d case status of NoWall -> turnLeft Blocked -> turnRight roomFollow f s dTurn
Left
No Wall
Wallleft
WallFollowLeft
Turn Right
Blocked
Free
Real-Time FRP (RT-FRP)Real-Time FRP (RT-FRP)• Abstract, restricted subset of FRP.• Behaviors and events captured uniformly as signals:
s ::= input | time | ext e | delay v s| let signal x = s1 in s2
| s1 switch on x = ev in s2
• Expressive enough to encode most of FRP. For example, integration by the forward Euler method:
integral s = let signal t = time in let signal v = s in let signal st = delay (0,(0,0)) (ext (i,
(v,t)) where (i0,(v0,t0)) = st i = i0 + v0(t - t0)) in ext (fst st)
Operational Semantics of RT-Operational Semantics of RT-FRPFRP
• Two judgements:Γ, Δ |– s : tE,K |– s i,t s’, v
• Key: constrain higher-order behaviors and recursion.– well-formed and tail-recursive
• Results:– Type safety / preservation.– Each step takes constant time (thus no time leaks).– Term size cannot grow (thus no space leaks).
• So far only theoretical result. We need to:– Compile FRP (when possible) into RT-FRP core.– Compile RT-FRP into lower-level code (C, etc).– Consider application to embedded systems.
Ongoing WorkOngoing Work• Vision-based Control (FVision).• Language enhancements (“running”
behaviors, time transformations, parallel tasks, etc).
• Multiple robots and RoboCup soccer.• Teaching robotics using Frob.• Better implementation / optimization.• Better tools (debugging, profiling, etc).• “Visual FRP”.• Graphical user interfaces.• Formal semantics / verification.• Real-time control and embedded systems.
For Further Reading...For Further Reading...
• The Haskell School of Expression -- Learning Functional Programming through Multimedia
• Cambridge University Press• Teaches functional programming using
Haskell, including three DSL’s: a Fran-like language (FAL), a Haskore-like language (MDL), and an imperative robot language (IRL).
• Available now from your favorite bookstore…
GloveGlove
by Tom Makucevichby Tom Makucevich
with help from Paul Hudakwith help from Paul Hudak
Composed using Haskore, a Haskell DSL,Composed using Haskore, a Haskell DSL,and rendered using csound.and rendered using csound.
How to Hide a Flock of How to Hide a Flock of TurkeysTurkeys
ConclusionsConclusions
• Domain Specific Languages are a Good Thing.• Embedded DSL’s (ala Haskell) can be used to implement highly effective programming environments.• “Functional Reactive Programming” is a good abstraction for many real-time reactive domains.• The programming languages community has some good ideas; let’s start using them!• DSL technology is fertile ground for programming language research.
There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.
---C.A.R. Hoare
A Formal Semantics for A Formal Semantics for FRPFRP
• What should an operational or denotational semantics for FRP look like?
• How is Time represented?• Are all continuous behaviors well-
behaved?• In what sense is an implementation (which
must approximate continuous behaviors) faithful to a formal semantics?
Some Key Design Some Key Design IssuesIssues
• Recursion vs. combinatorsuntil, switch :: Beh a -> Event (Beh a) -> Beh ab `switch` e = b `until` e ==> \b1 -> b1 `switch`
e
• A rich algebra of eventslbp :: Event ( ); key :: Event Char(==>) :: Event a -> (a->b) -> Event baccum :: a -> Event (a -> a) -> Event asnapshot :: Event a -> Behavior b -> Event (a,b)when :: Behavior Bool -> Event ( )(.|.) :: Event a -> Event a -> Event a
Domain Specific Domain Specific TransformationsTransformations
• Many domains exhibit nice algebraic properties, with which one can reason about, transform, and optimize programs.
• Query optimization in databases is the prototypical example.
• An implementation can often be proven correct with respect to these properties.
• But we cannot expect a general purpose compiler to perform these optimizations for us.
• We need source level meta-programming tools.
Example: Simple GraphicsExample: Simple Graphics -- Atomic objects: circle -- a unit circle square -- a unit square importGIF "p.gif" -- an imported bit-map
-- Composite objects: scale v p -- scale picture p by vector v color c p -- color picture p with color c trans v p -- translate picture p by vector v p1 `over` p2 -- overlay p1 on p2 p1 `above` p2 -- place p1 above p2 p1 `beside` p2 -- place p1 beside p2
-- Axioms over, above, and beside are associative scale, color, and trans distribute over over, above, & beside scale is multiplicative, trans is additive etc.
Thus an algebra of graphics emerges.
Simple AnimationsSimple Animations type Behavior a = Time -> a type Animation = Behavior Picture
Now we “lift” the simple graphics operations to work on behaviors as well. For example:
(b1 `overB` b2) t = b1 t `over` b2 t (b1 `aboveB` b2) t = b1 t `above` b2 t (b1 `besideB` b2) t = b1 t `beside` b2 t
(scaleB v b) t = scale (v t) (b t) (colorB c b) t = color (c t) (b t) (transB v b) t = trans (v t) (b t)
And a new function to express the current time:
time t = t
All previous graphics axioms hold for animations.
Visual LanguagesVisual Languages
• In some domains, the most common notation is pictorial.
• For example: signal processing, digital hardware design, control systems, and sound synthesis.
• Should Fran / FRP be a visual programming language, and if so, what should it look like?
• We need tools to provide both views of a program.