31
Halogen: Past, Present, Future John A. De Goes — @jdegoes

Halogen: Past, Present, and Future

Embed Size (px)

Citation preview

Page 1: Halogen: Past, Present, and Future

Halogen: Past, Present, FutureJohn A. De Goes — @jdegoes

Page 2: Halogen: Past, Present, and Future

Agenda• Functional Frontend: SlamData• FRP & React

• Common Elements• FRP in a Type• React in a Type• The 100k Problem• Turtles

• Halogen: Introduction• Halogen: Past• Halogen: Present• Halogen: Future• Conclusion

Page 3: Halogen: Past, Present, and Future

Functional Frontend: SlamData• Visual analytics for NoSQL

• Analytic workflows• Data exploration• Data visualization

• 100% PureScript• 248 modules• Largest known PureScript project in the world• Currently five full-time developers

Page 4: Halogen: Past, Present, and Future

Data VisualizationWe'll get back to that.

Page 5: Halogen: Past, Present, and Future

FRP & ReactCommon Elementsdata HTML i = Text String | Element TagName (A.Attribute i) (Array (HTML i))

data HTML = Text String | Element TagName A.Attribute (Array HTML)

Page 6: Halogen: Past, Present, and Future

FRP & ReactFRP in a Typedata Signal a = Signal (Time -> a)

instance applicativeSignal :: ...

myApp :: Signal HTMLmyApp = ...

Page 7: Halogen: Past, Present, and Future

FRP & ReactReact in a Typedata React s m i = React { render :: s -> HTML i, update :: i -> s -> m s }

myApp :: React MyState EffectMonad MyEventmyApp = ...

Page 8: Halogen: Past, Present, and Future

The 100k ProblemLook Closely...Signal HTML

s -> HTML a

Types necessarily imply a potentially massive, in-memory HTML structure that can neither be created nor updated incrementally.

Page 9: Halogen: Past, Present, and Future

The 100k ProblemDiffingdiff :: HTML -> HTML -> HTMLPatch

Diffing only helps with the DOM updates, nothing else!

Page 10: Halogen: Past, Present, and Future

The 100k ProblemData VisualizationNeither React nor FRP offer a performant means of incrementally visualizing large data sets. Rendering or even storing that much data is prohibitive.

Page 11: Halogen: Past, Present, and Future

Halogen: PastHistory• Popular, production-ready UI library for PureScript• Commissioned by SlamData

• Blank-slate design originally architected by Phil Freeman• Powers the SlamData application

Page 12: Halogen: Past, Present, and Future

Halogen: PastSignal Functionsdata HTML i = ...

newtype SF i o = SF (i -> SF1 i o)

newtype SF1 i o = SF1 { result :: o, next :: SF i o }

type UI i = SF1 i (HTML i)

runUI :: forall i eff. UI i -> Eff (HalogenEffects eff) Node

Page 13: Halogen: Past, Present, and Future

Halogen: PastIf You Squint...type Function i o = i -> o

type UI i = Cofree (Function i) (HTML i)

Page 14: Halogen: Past, Present, and Future

Halogen: PresentView + DSLtype Component s f g = { view :: s -> HTML (f Unit), eval :: forall a. f a -> (HalogenDSL s g) a }

Grossly simplified. :)

Page 15: Halogen: Past, Present, and Future

Halogen: PresentIn Practice• Strongly-typed component-driven design• Structure of entire app is encoded in type (!!!)

• ...And therefore static (pros & cons)• Types get complex, but reasoning is level-by-level• Hard to get compiling, but then usually works

Page 16: Halogen: Past, Present, and Future

Halogen: FutureNext-Generation Goals• Built on a foundation of incremental computation• Turtles all the way down — no magic• Native expressivity — no need for escape hatch• Unify web components with ordinary HTML

"components" (elements)• Simplify types a little? :)

Page 17: Halogen: Past, Present, and Future

Halogen: FutureIncremental React???data React s m i = React { render :: s -> HTML i, update :: i -> s -> m s }

data DReact s ds m i = DReact { render :: s -> ds -> ΔHTML i, effect :: i -> s -> m ds, update :: s -> ds -> s }

Page 18: Halogen: Past, Present, and Future

Halogen: FutureSimplifydata UI s p i ds = UI { render :: s -> p i ds, -- Push "effects" here! update :: s -> ds -> s } -- Monoid action!

• Rendering produces a machine that reads is and produces a state change.

• Updating produces a new state given an old state and a state change.

Page 19: Halogen: Past, Present, and Future

Halogen: FutureProfunctor Algebrasdata File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b)

Page 20: Halogen: Past, Present, and Future

Halogen: FutureProfunctor Algebras Contravariant |data File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b)

Page 21: Halogen: Past, Present, and Future

Halogen: FutureProfunctor Algebras Covariant |data File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b)

Page 22: Halogen: Past, Present, and Future

Halogen: FutureProfunctor Algebrasdata FreePro p a b -- :: (* -> * -> *) -> * -> * -> *

A computation in p that reads 0-to-many a's and produces a single b.

• Functor, Apply, Applicative, Monad (if desired)• Profunctor

Page 23: Halogen: Past, Present, and Future

Halogen: FutureProfunctor Algebrasdata File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b)

readByte :: FreePro File Byte BytereadByte = liftFP $ ReadByte id

writeByte :: forall a. Byte -> FreePro a UnitwriteByte b = liftFP $ WriteByte b id

Page 24: Halogen: Past, Present, and Future

Halogen: FutureProfunctor Algebrasdata DOM i o = ListenEvent Id EventType (i -> Event) | AppendChild Id (Id -> o) | ...

Page 25: Halogen: Past, Present, and Future

Halogen: FutureProfunctor Algebrasdata UI s p i ds = UI { render :: s -> p i ds, update :: s -> ds -> s }

type FreeDOM a b = FreePro DOM a b

type Component s ds = UI s FreeDOM DOMEvent ds

Page 26: Halogen: Past, Present, and Future

Halogen: FutureComponentsdata TextDiff = Insert Int String | Delete Int Int

textField :: Component String TextDiff

*Can be more polymorphic!

Page 27: Halogen: Past, Present, and Future

Halogen: FutureLens-ishdata Nest ds' s' ds s = Nest (PrismP ds' ds) (LensP s' s)

The nesting of a smaller state differential inside a larger one.

Page 28: Halogen: Past, Present, and Future

Halogen: FutureCombinatorsembed :: forall ds' s' ds s. Nest ds' s' ds s -> Components ds' s' -> Components ds s

siblings :: forall s ds. Component s ds -> Component s ds -> Component s dschild :: forall s ds. Component s ds -> Component s ds -> Component s ds

infix 5 siblings as <~>infix 6 child as </>

Page 29: Halogen: Past, Present, and Future

Halogen: FutureExampledata FormDiff = Email TextDiff | Password TextDiff

type FormState = { email :: String, password :: String }

webForm :: Component FormState FormDiffwebForm = div </> embed _Email (label "Email" <~> textField) <~> div </> embed _Password (label "Password" <~> passwordField)

_Email :: Nest String TextDiff FormState FormDiff_Password :: Nest String TextDiff FormState FormDiff

Page 30: Halogen: Past, Present, and Future

Conclusion• Practical requirements suggest an incremental theory of UI• FRP and React are problematic• A coinductive, profunctor-based approach looks promising

• But some details yet to be worked out...• Halogen 1.0 is coming, & you can help!

Page 31: Halogen: Past, Present, and Future

THANK YOU!John A. De Goes — @jdegoes