Functional reactive programming Future values Improving values Unambiguous choice Push-pull functional reactive programming Conal Elliott 3 September, 2009 Haskell Symposium Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Improving values Unambiguous choice 1 Functional reactive programming Semantics Building blocks Refactoring 2 Future values Class instances Future times 3 Improving values Description and problems Improving 4 Unambiguous choice Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice What is Functional Reactive Programming? Composable dynamic values, . . . with simple & precise semantics. Continuous time (zoomable). Fine-grain, deterministic concurrency. Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Classic FRP – semantic model Behaviors (signals) are flows of values, punctuated by event occurrences. [ [ Behavior α ] ] = T → α = [ � T × α ] [ [ Event α ] ] -- monotonic Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Behaviors compose time :: Behavior T [ [ time ] ] = id pure :: α → Behavior α [ [ pure a ] ] = λ t → a = pure a ( < ∗ > ) :: Behavior α → β → Behavior α → Behavior β [ [ fs < ∗ > as ] ] = λ t → (([ [ fs ] ] t ) ([ [ as ] ] t )) = [ [ fs ] ] < ∗ > [ [ as ] ] Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Events compose ∅ :: Event α [ [ ∅ ] ] = [ ] ( ⊕ ) :: Event α → Event α → Event α [ e ⊕ e ′ ] [ e ′ ] [ ] = [ [ e ] ] ‘ merge ‘ [ ] fmap n :: ( α → β ) → Event α → Event β [ [ fmap f e ] ] = map ( λ ( t , a ) → ( t , f a )) [ [ e ] ] = fmap ( fmap f ) [ [ e ] ] Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Events punctuate behaviors stepper :: α → Event α → Behavior α More generally, switcher :: Behavior α → Event Behavior α → Behavior α Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Main idea of the paper: Behaviors are chains of simple phases So represent as such: Behavior a = ( T → a ) × ( � T × Behavior a ) Catch: We need lazy expiration times . Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Generalize/simplify – Reactive values Behavior α = ( T → α ) × ( � T × Behavior α ) Generalize: Reactive β = β × ( � T × Reactive β ) -- discrete reactive And specialize: [ [ TFun α ] ] = T → α -- continuous non-reactive Behavior = Reactive ◦ TFun This representation provides Functor and Applicative instances. Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice TFun constant-folds data Fun t a = K a | Fun ( t → a ) [ [ Fun t a ] ] = t → a data TFun = Fun T [ [ K a ] ] = const a [ [ Fun f ] ] = f instance Functor ( TFun t ) where fmap f ( K a ) = K ( f a ) fmap f ( Fun g ) = Fun ( f ◦ g ) etc Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Generalize/simplify – Future values Reactive β = β × ( � T × Reactive β ) becomes = � T × γ Future γ Reactive β = β × Future Reactive β Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Events are future reactives Reactive β = β × Future Reactive β becomes Event α = Future Reactive α Reactive β = β × Event β Conal Elliott Push-pull functional reactive programming
Functional reactive programming Semantics Future values Building blocks Improving values Refactoring Unambiguous choice Summarizing = � T × γ Future γ Event α = Future Reactive α Reactive β = β × Event β Behavior = Reactive ◦ TFun data Fun t a = K a | Fun ( t → a ) Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Class instances Improving values Future times Unambiguous choice Future values are mostly easy newtype Future α = Fut ( � T , α ) deriving ( Functor , Applicative , Monad ) For Applicative and Monad , the � T monoid uses max and −∞ . Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Class instances Improving values Future times Unambiguous choice What about Monoid? A first try: ( ⊕ ) chooses the earlier of two futures: instance Monoid ( Future α ) where ∅ = Fut ( ∞ , ⊥ ) u a @( Fut (ˆ t a , )) ⊕ u b @( Fut (ˆ t b , )) = if ˆ t a � ˆ t b then u a else u b We’ll have to compare future times without knowing both fully. Even so, there’s a problem ... Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Class instances Improving values Future times Unambiguous choice ( ⊕ ) must be even lazier. First try: u a @( Fut (ˆ t a , )) ⊕ u b @( Fut (ˆ t b , )) = if ˆ t a � ˆ t b then u a else u b Produces no information until resolving ˆ t a � ˆ t b . Consider ( u a ⊕ u b ) ⊕ u c , where u c is earliest. Oops . Solution: Fut (ˆ t a , a ) ⊕ Fut (ˆ t b , b ) = Fut (ˆ t a ‘ min ‘ ˆ t b , if ˆ t a � ˆ t b then a else b ) Can be optimized. Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Class instances Improving values Future times Unambiguous choice What are future times? type � T = Max ( AddBounds ( Improving T )) Max monoid for derived Applicative Future (and Monad ) AddBounds for the Future and Max monoids Improving for partiality Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Description and problems Improving values Improving Unambiguous choice What are improving values? Lazy values, as a monotonic sequence of lower bounds Invented by Warren Burton in the 1980s Operations for min and max Purely functional implementation Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Description and problems Improving values Improving Unambiguous choice Improving values have some problems. Expensive to step through accumulated lower bounds Redundant traversal Needs a generator of lower bounds Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Description and problems Improving values Improving Unambiguous choice Can we improve on improving values? What operations do we use on � T ? exact :: Improving a → a compare I :: Improving a → a → Ordering :: Improving a → Improving a → Improving a min :: Improving a → Improving a → Bool ( � ) Puzzle: Can exact and compare I implement min and ( � )? If so, data Improving a = Imp { exact :: a , compare I :: a → Ordering } Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Description and problems Improving values Improving Unambiguous choice Comparing improving values – dilemma How to compare future times: ˆ t a � ˆ t b ? Two ideas: ab = compare I ˆ t a ( exact ˆ t b ) �≡ GT ba = compare I ˆ t b ( exact ˆ t a ) �≡ LT Which to try first? We can’t know beforehand. Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Improving values Unambiguous choice Try both Same answer when defined, so try in parallel and take first answer ab ‘ unamb ‘ ba Referentially transparent? Yes: ab ‘ unamb ‘ ba ≡ ab ⊔ ba Crucial: ab and ba agree when defined. Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Improving values Unambiguous choice unamb is handy parCommute op x y = ( x ‘ op ‘ y ) ‘ unamb ‘ ( y ‘ op ‘ x ) por = parCommute ( ∨ ) pand = parCommute ( ∧ ) -- handy with unamb assuming :: Bool → a → a assuming True a = a assuming False = ⊥ Conal Elliott Push-pull functional reactive programming
Functional reactive programming Future values Improving values Unambiguous choice Symmetric short-circuiting parAnnihilator op a x y = assuming ( x ≡ a ) a ‘ unamb ‘ assuming ( y ≡ a ) a ‘ unamb ‘ ( x ‘ op ‘ y ) = parAnnihilator ( ∨ ) True por pand = parAnnihilator ( ∧ ) False pmul = parAnnihilator ( × ) 0 pmin = parAnnihilator min minBound pmax = parAnnihilator max maxBound Conal Elliott Push-pull functional reactive programming
Recommend
More recommend