Title: Haskell in Motion An Introduction to FRP
1Haskell in Motion An Introduction to FRP
- Zhanyong Wan, Yale University
- 3/23/2001
2What Is FRP
- A Domain-Specific Language
- Not general-purpose
- For hybrid reactive systems
- Embedded in Haskell
- Isnt compiled by a compiler written in Haskell
- Isnt compiled into Haskell
- Is a collection of Haskell data types and
functions
3General-Purpose vs. Domain-Specific
- General-purpose programming languages
- Want to solve all problems in one framework
- Have to make trade-offs when designing the
language - Expressiveness vs. Efficiency
- Do not possess domain knowledge
- Can not always make the right trade-offs
- Not abstract enough
- Not optimized for the domain
4Writing Animation in GP Languages
- Sketch of the code (taken from Elliotts Fran
manual) - allocate and initialize window, various drawing
surfaces and bitmaps - repeat until quit
- get time ( t )
- clear back buffer
- for each sprite (back to front)
- compute position, scale, etc. at t
- draw to back buffer
- flip back buffer to the screen
- deallocate bitmaps, drawing surfaces, window
- Lots of tedious, low-level code that you have to
write yourself - A better way exists!
5Domain-Specific Languages
- DSLs
- Not intended to be general-purpose
- Aimed at solving problems in a particular domain
- Why DSLs?
- Designed with the problem domain in mind
- Capture the right abstraction
- Let the programmer concentrate on the problem,
not low-level details - Examples
- HTML, SQL, Shell in UNIX, Perl, Prolog
6Domain-Specific Languages (contd)
- Haskell as the vehicle for DSLs
- Flexible syntax
- User-defined operators, infix usage of functions
- Powerful type system
- Higher-order
- Control structures
- Referentially transparent imperative programming
via monads - Polymorphic
- Abstract code
- Reusable
- Declarative
- Quick prototyping
- Good for testing new language constructs and
design ideas - Embedded DSL inherits Haskells syntax and type
system
7Reactive Programming
- Reactive systems
- Continuously react to stimuli
- Environment cannot wait
- Conceptually, values can change over continuous
time - Examples
- Interactive animation
- GUI
- Robotics
- Control systems
- Traditional languages do a poor job
- Discrete sampling
- The animation example
8Benefits of FRP
- High-level, declarative
- Concise code
- Executable spec
- new! Time is continuous
9What Is FRP Good for?
- Applications of FRP
- Fran Elliott and Hudak Interactive animation
- Frob Peterson, Hager, Hudak and Elliott
Robotics - FVision Reid, Peterson, Hudak and Hager Vision
- Frappé Courtney Java
- FranTk Sage GUI
moveXY (sin timeB) 0 charlotte charlotte
importBitmap charlotte.bmp
10Essential Haskell Features Used
- Higher-order functions
- Lazy streams
- Infix operators
- Type classes
- Multi-parameter type classes
- Functional dependency
- IO monad
- Interaction with the environment
- Memoization
- Monads
- Tasks
11Using FRP
- Resources
- http//haskell.org/frp
- Manual http//haskell.org/frp/manual.html
- How to use
- In the Zoo
- /usr/local/bin/rugs
- /usr/local/hugs/frp/
- /usr/local/hugs/frob/
- At home
- Copy the files from Zoo
- On Linux rugs
- On Windows hugs -98
12Basic Concepts
- Behaviors (Behavior i a)
- Reactive, continuous-time-varying values
- timeB Behavior i Time
- mouseB GuiInput i gt Behavior i Point2
- Events (Event i a)
- Streams of discrete event occurrences
- lbpE GuiInput i gt Event i ()
- Switching
- b1 till lbpE -gt b2
- Combinators
- Behaviors and events are both first-class
- Passed as arguments
- Returned by functions
- Composed using combinators
13Behaviors
- Time
- timeB Behavior i Time
- Input
- mouseB GuiInput i gt Behavior i Point2
- Integration
- integralB Behavior i FRPReal
- -gt Behavior i FRPReal
- (integralB timeB)
- Constant behaviors
- lift0 a -gt Behavior i a
- (lift0 5)
14Lifting
- Static value -gt behavior
- lift0 a -gt Behavior i a
- lift1 (a -gt b) -gt Behavior i a -gt Behavior i b
- lift2 (a -gt b -gt c)
- -gt Behavior i a -gt Behavior i b -gt Behavior
i c - ...
- Examples
- lift1 sin timeB
- lift2 () (lift0 1) (lift1 sin timeB)
time
time
15Simplify the Syntax
- Can we make lifting implicit?
- lift2 () (lift0 1) (lift1 sin timeB)
- gt 1 sin timeB
- Sometimes, Yes!
16Demo Simple Behaviors
demo
- Hello, world!
- hello Behavior i Picture
- hello text lift0 "Hello, world!"
- main1 animate hello
- Interaction mouse-following
- main2 animate moveTo mouseB hello
- Time
- main3 animate text lift1 show timeB
17Geometry in FRP
- 2-D
- Points
- Vectors
- Common shapes
- Circle, line, polygon, arc, and etc
- Affine transformations
- Rotation
- Translation
- Reflection
- Scaling
- Shear
- Composition of the above
- 3-D as well
18Demo Spatial Transformations
demo
- Spatial transformations -- dancing ball
- ball Behavior i Picture
- ball withColor red stretch 0.1 circle
- wiggle, waggle
- Behavior i FRPReal -gt Behavior i FRPReal
- wiggle omega sin (omegatimeB)
- waggle omega cos (omegatimeB)
- main4 om1 om2 animate
- moveXY (wiggle om1) (waggle om2)
- moveTo mouseB ball
19Demo Spatial Composition
demo
- Spatial composition -- dancing ball text
- main5 animate moveTo mouseB
- moveXY (wiggle 4) (waggle 4) ball over
- moveXY (wiggle 7) (waggle 3) hello
20Demo Recursive Behaviors
- Damped motion of a mass dragged with a spring
- Integral equations
- Recursive
d pm po a ksd kfv v ? a dt po ? v dt
d
pm
v
po
ks d
-kf v
21Demo Recursive Behaviors (contd)
demo
- FRP Code
- moveTo po ball
- where
- ks 1
- kf 0.8
- d mouseB .-. po
- a ks d kf v
- v integralB a
- po vector2ToPoint2 integralB v
- Declarative
- Concise
- Recursive
d pm po a ksd kfv v ? a dt po ? v dt
22Events
- User events
- lbpE GuiInput i gt Event i ()
- Predicate events
- whenE Behavior i Bool -gt Event i ()
- Trivial events
- neverE Event i a
23Events (contd)
- Composite events
- (..) Event i a -gt Event i a -gt Event i a
- bothE Event i a -gt Event i b -gt Event i
(a,b) - filterE Event i a -gt (a -gt Bool) -gt Event i a
- (gt) Event i a -gt (a -gt b) -gt Event i b
- (-gt) Event i a -gt b -gt Event i b
- e -gt b e gt const b
- onceE Event i a -gt Event i a
- accumE a -gt Event i (a-gta) -gt Event i a
- snapshotE Event i a -gt Behavior i b
- -gt Event i (a,b)
24Switching
- Mode switching
- A common pattern in reactive systems
- Till
- till Behavior i a -gt Event i (Behavior i a)
- -gt Behavior i a
- Switch
- switch Behavior i a -gt Event i (Behavior i a)
- -gt Behavior i a
- Higher-order events
- Event algebra
25Demo Switching
demo
- Switching of behaviors
- color GuiInput i gt Behavior i Color
- color red till lbpE -gt blue
- mouseBall GuiInput i gt Behavior i Picture
- mouseBall moveTo mouseB stretch 0.5 circle
- main7 animate withColor color mouseBall
- Recursive switching
- cycle3 c1 c2 c3 c1 till lbpE
- -gt cycle3 c2 c3 c1
- main8 animate
- withColor (cycle3 red green blue) mouseBall
26Demo Event Merging
demo
- Making choices
- main9 animate
- withColor (green switch
- (lbpE -gt blue .. rbpE -gt red))
- mouseBall
- Higher-order events help
27Other Demos
demo
- Paddle ball
- Simulates robots
- Large
- 100 pure FRP
28Inside Haskell the Numeric
demo
- Case study
- f Int -gt Bool
- g Double -gt Bool
- f 5 -- well-typed
- g 5 -- well-typed
- f 5.6 -- ill-typed!
- g 5.6 -- well-typed
- How does this work?
- 5 ?
- 5.6 ?
- No C/Java style implicit coercion in Haskell
- 5 Int ?
- 5 Double ?
29Inside Haskell the Numeric (contd)
- Numbers are polymorphic!
- 5 Num a gt a
- 5.6 Fractional a gt a
- Numeric operators are polymorphic too
- () Num a gt a -gt a -gt a
- sin Floating a gt a -gt a
- Numeric classes
- class Num a
- class Num a gt Fractional a
- class Fractional a gt Floating a
- instance Num Int/Integer/Float/Double/
... - instance Fractional Float/Double/...
- instance Floating Float/Double/...
30How Does This Work?
- Numbers are polymorphic
- 5 Num a gt a
- Haskells open-world assumption
- always possible to add new instances to a class
- Numeric literals must work for new Num instances!
- Binary numbers
- data Bit Zero One
- newtype Bin Bin Bit
- instance Num Bin
- Should accept 5 where a Bin is expected!
- But how?
31Inside Haskell the Numeric (contd)
demo
- Haskell treats numbers in a special way
- 5 is shorthand for fromInteger 5
- 5.6 is shorthand for fromRational 5.6
- And so on
- Implementing Bin
- instance Num Bin where
- ...
- fromInteger 0 Bin Zero
- fromInteger 1 Bin One
- fromInteger n
- n lt 0
- error "Bin negative number not
supported." - fromInteger n Bin (bits bit) where
- Bin bits fromInteger (n div 2)
- Bin bit fromInteger (n mod 2)
32Simplify Lifting Syntax
- Numeric literals lift themselves
- instance Num a gt Num (Behavior i a) where
- fromInteger lift0 . fromInteger
- instance Fractional a gt Fractional (Behavior i
a) where - fromRational lift0 . fromRational
- Numeric operators lift themselves too
- instance Num a gt Num (Behavior i a) where
- () lift2 ()
- instance Floating a gt Floating (Behavior i a)
where - sin lift1 sin
- Now possible
- lift2 () (lift0 1) (lift1 sin timeB)
- gt 1 sin timeB
33Overloading Not Always Possible
- Built-in operators/functions
- () Eq a gt a -gt a -gt Bool
- Lifted
- () Eq a gt
- Behavior i a -gt Behavior i a -gt Bool
- Not
- () Eq a gt
- Behavior i a -gt Behavior i a -gt Behavior i
Bool - The -suffix convention
- () Eq a gt
- Behavior i a -gt Behavior i a -gt Behavior i
Bool - User-defined operators/functions
- Polymorphic definition
- Explicit lifting
34End of Lecture
- Slides available at
- http//haskell.org/frp/frp-intro.ppt