Slide 1

Slide 1 text

purescript-incremental Phil Freeman

Slide 2

Slide 2 text

Why? We want to avoid recomputing things unnecessarily

Slide 3

Slide 3 text

Why? SELECT MIN(cost), MAX(cost) FROM products WHERE type = ‘Rubber Stamp’;

Slide 4

Slide 4 text

Why? SELECT SUM(orders.total) FROM orders JOIN customer ON customers.id = orders.customer_id WHERE customer.state = ‘CA’;

Slide 5

Slide 5 text

Idea Instead, we can try to compute changes in outputs from changes in inputs.

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Incremental Lambda Calculus Extend types with change structures Change structures are monoids of changes which act on their carrier types (transitively).

Slide 8

Slide 8 text

In Brief class Patch a da ⇐ Diff a da | a → da where diff :: a → a → da instance Diff Unit Unit instance (Diff a da, Diff a db) ⇒ Patch (Diff a b) (Diff da db) instance (Diff a da, Diff a db) ⇒ Diff (a → b) (a → da → db) instance Diff a da ⇒ Diff (Bag a) (Bag da) class Monoid da ⇐ Patch a da | a → da where patch :: a → da → a instance Patch Unit Unit instance (Patch a da, Patch a db) ⇒ Patch (Tuple a b) (Tuple da db) instance (Patch a da, Patch a db) ⇒ Patch (a → b) (a → da → db) instance Patch a da ⇒ Patch (Bag a) (Bag da)

Slide 9

Slide 9 text

A Theory of Changes for Higher-Order Languages Interpret each type as a type and a change structure Construct a source-to-source transformation to interpret terms

Slide 10

Slide 10 text

purescript-incremental Defines an embedded DSL for incremental programs ● Uses higher-order abstract syntax ● Inspired by automatic differentiation

Slide 11

Slide 11 text

purescript-incremental unjet :: (Jet a da → Jet b db) → Tuple (a → b) (a → da → db) unjet jf = Tuple f df where f a = b where Jet b _ = jf (Jet a mempty) df a da = db where Jet _ db = jf (Jet a da) jet :: (a → b) → (a → da → db) → Jet a da → Jet b db jet f df (Jet a da) = Jet (f a) (df a da) data Jet a da = Jet a da

Slide 12

Slide 12 text

Embedding We require that patch (f₀ a) db = f₀ (patch a da) whenever Jet _ db = f (Jet a da) Tuple f₀ _ = unjet f “Constant” jet functions also satisfy snd (f (Jet a mempty)) = mempty Represent a function a → b by f :: Jet a da → Jet b db

Slide 13

Slide 13 text

Example map :: (Jet a da -> Jet b db) → Jet (IMap k a) _ → Jet (IMap k b) _ filter :: (Jet a da -> Jet Boolean _) → Jet (IMap k a) _ → Jet (IMap k a) _ join :: Jet (IMap k a) _ → Jet (IMap k b) _ → Jet (IMap k (Tuple a b)) _ Embedded incremental relational algebra! data IMap k v data MapChange v dv = Add v | Remove | Update dv type MapChanges k v dv = Map k (Array (MapChange v dv)) instance Patch v dv ⇒ Patch (IMap k v) (MapChanges k v dv)

Slide 14

Slide 14 text

Incremental DOM newtype ViewChanges eff = ViewChanges { text :: Last String , attrs :: MapChanges String (Atomic String) (Last String) , handlers :: MapChanges String (Atomic (EventListener eff)) (Last (EventListener eff)) , kids :: Array (ArrayChange (View eff) (ViewChanges eff)) } Translate model changes directly into DOM updates. See purescript-purview. newtype View eff = View { element :: String , text :: Atomic String , attrs :: IMap String (Atomic String) , handlers :: IMap String (Atomic (EventListener eff)) , kids :: IArray (View eff) }

Slide 15

Slide 15 text

Stuff to think about ● Some similar DOM libraries ○ paf31/purescript-sdom ○ i-am-tom/purescript-panda ● Implement this in the database ● Incremental parsing ● Incremental canvas graphics Questions?