Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Halogen: Past, Present, and Future

2,119 views

Published on

Halogen is a popular choice for building front-end user-interfaces with PureScript. Often described as a purely functional version of React, Halogen allows building user-interfaces by composing declarative, self-contained components, including effectful components those built from third-party Javascript libraries.

In this presentation, John presents a high-level summary of where Halogen has come from, how it works right now, and what are the main drawbacks to both FRP and React. John then suggests that incremental computation should be the foundation for the next major version of Halogen, and sketches out a possible way of achieving that in a declarative fashion.

Published in: Technology

Halogen: Past, Present, and Future

  1. 1. Halogen: Past, Present, Future John A. De Goes — @jdegoes
  2. 2. 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
  3. 3. 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
  4. 4. Data Visualization We'll get back to that.
  5. 5. FRP & React Common Elements data HTML i = Text String | Element TagName (A.Attribute i) (Array (HTML i)) data HTML = Text String | Element TagName A.Attribute (Array HTML)
  6. 6. FRP & React FRP in a Type data Signal a = Signal (Time -> a) instance applicativeSignal :: ... myApp :: Signal HTML myApp = ...
  7. 7. FRP & React React in a Type data React s m i = React { render :: s -> HTML i, update :: i -> s -> m s } myApp :: React MyState EffectMonad MyEvent myApp = ...
  8. 8. The 100k Problem Look Closely... Signal HTML s -> HTML a Types necessarily imply a potentially massive, in-memory HTML structure that can neither be created nor updated incrementally.
  9. 9. The 100k Problem Diffing diff :: HTML -> HTML -> HTMLPatch Diffing only helps with the DOM updates, nothing else!
  10. 10. The 100k Problem Data Visualization Neither React nor FRP offer a performant means of incrementally visualizing large data sets. Rendering or even storing that much data is prohibitive.
  11. 11. Halogen: Past History • Popular, production-ready UI library for PureScript • Commissioned by SlamData • Blank-slate design originally architected by Phil Freeman • Powers the SlamData application
  12. 12. Halogen: Past Signal Functions data 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
  13. 13. Halogen: Past If You Squint... type Function i o = i -> o type UI i = Cofree (Function i) (HTML i)
  14. 14. Halogen: Present View + DSL type Component s f g = { view :: s -> HTML (f Unit), eval :: forall a. f a -> (HalogenDSL s g) a } Grossly simplified. :)
  15. 15. Halogen: Present In 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
  16. 16. Halogen: Future Next-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? :)
  17. 17. Halogen: Future Incremental 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 }
  18. 18. Halogen: Future Simplify data 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.
  19. 19. Halogen: Future Profunctor Algebras data File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b)
  20. 20. Halogen: Future Profunctor Algebras Contravariant | data File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b)
  21. 21. Halogen: Future Profunctor Algebras Covariant | data File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b)
  22. 22. Halogen: Future Profunctor Algebras data 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
  23. 23. Halogen: Future Profunctor Algebras data File a b = ReadByte (a -> Byte) | WriteByte Byte (Unit -> b) readByte :: FreePro File Byte Byte readByte = liftFP $ ReadByte id writeByte :: forall a. Byte -> FreePro a Unit writeByte b = liftFP $ WriteByte b id
  24. 24. Halogen: Future Profunctor Algebras data DOM i o = ListenEvent Id EventType (i -> Event) | AppendChild Id (Id -> o) | ...
  25. 25. Halogen: Future Profunctor Algebras data 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
  26. 26. Halogen: Future Components data TextDiff = Insert Int String | Delete Int Int textField :: Component String TextDiff *Can be more polymorphic!
  27. 27. Halogen: Future Lens-ish data Nest ds' s' ds s = Nest (PrismP ds' ds) (LensP s' s) The nesting of a smaller state differential inside a larger one.
  28. 28. Halogen: Future Combinators embed :: 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 ds child :: forall s ds. Component s ds -> Component s ds -> Component s ds infix 5 siblings as <~> infix 6 child as </>
  29. 29. Halogen: Future Example data FormDiff = Email TextDiff | Password TextDiff type FormState = { email :: String, password :: String } webForm :: Component FormState FormDiff webForm = div </> embed _Email (label "Email" <~> textField) <~> div </> embed _Password (label "Password" <~> passwordField) _Email :: Nest String TextDiff FormState FormDiff _Password :: Nest String TextDiff FormState FormDiff
  30. 30. 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!
  31. 31. THANK YOU! John A. De Goes — @jdegoes

×