$30 off During Our Annual Pro Sale. View Details »

PureScript & Halogen

PureScript & Halogen

Bucharest FP

May 08, 2018
Tweet

More Decks by Bucharest FP

Other Decks in Programming

Transcript

  1. PureScript & Halogen
    Vladimir Ciobanu
    Tuesday, May 8, 2018
    Development Lead, Visual Solutions, Mood Media Romania

    View Slide

  2. Overview
    Why Not...
    Introduction to PureScript
    My PureScript Workflow
    Halogen
    Conclusion
    1

    View Slide

  3. Why Not...

    View Slide

  4. Why Not JavaScript?
    • very loose language
    (coercions, quirks, etc)
    • easy to hack something
    together, hard to keep it
    sane
    • practically inexistent type
    system
    • npm is a mess
    • frequent breaking
    changes
    2

    View Slide

  5. What About TypeScript?
    TypeScript is a typed superset of JavaScript that compiles to
    plain JavaScript.
    • fails to fix a lot of problems (coercions, quirks are still
    there)
    • type definitions aren’t trivial to keep in sync
    • still missing a lot of advanced features (sum types, type
    classes, dependent types, etc)
    3

    View Slide

  6. Introduction to PureScript

    View Slide

  7. What is PureScript?
    PureScript is a strongly-typed functional programming
    language that compiles to JavaScript.
    • Compile to readable JavaScript
    • Strong FFI / interoperability with JavaScript
    • No runtime (unlike Elm, GHCJS, etc)
    • Very good tooling
    • Great community
    • High-quality libraries
    4

    View Slide

  8. Syntax - Functions
    1 addOne :: Int → Int
    2 addOne x = x + 1
    3
    4 head :: List Maybe
    5 head = case _ of
    6 Nil → Nothing
    7 Cons x _ → Just x
    8
    9 even :: Int → Boolean
    10 not :: Boolean → Boolean
    11
    12 notEven :: Int → Boolean
    13 notEven = not <<< even
    14
    15 headNotEven :: List Int → Maybe Boolean
    16 headNotEven = map notEven <<< head
    5

    View Slide

  9. JavaScript Output 1/2
    Head.purs
    1 head :: List Maybe
    2 head = case _ of
    3 Nil → Nothing
    4 Cons x _ → Just x
    output.js
    1 var head = function (v) {
    2 if (v instanceof Data_List_Types.Nil) {
    3 return Data_Maybe.Nothing.value;
    4 };
    5 if (v instanceof Data_List_Types.Cons) {
    6 return new Data_Maybe.Just(v.value0);
    7 };
    8 throw new Error("Failed pattern match at Main..");
    9 };
    6

    View Slide

  10. JavaScript Output 2/2
    HeadNotEven.purs
    1 headNotEven :: List Int → Maybe Boolean
    2 headNotEven = map notEven <<< head
    output.js
    1 var headNotEven = function ($5) {
    2 return Data_Functor.map
    3 (Data_Maybe.functorMaybe)(notEven)(head($5));
    4 };
    7

    View Slide

  11. Syntax - Records
    1 type Person r =
    2 { name :: String
    3 , age :: Int
    4 | r
    5 }
    6
    7 isOlderThan :: ∀ r1 r2. Person r1 → Person r2 → Boolean
    8 isOlderThan p1 p2 = p1.age > p2.age
    9
    10 isOlderThan’ :: ∀ r1 r2
    11 . { age :: Int | r1 }
    12 → { age :: Int | r2 }
    13 → Boolean
    14 isOlderThan’ p1 p2 = p1.age > p2.age
    8

    View Slide

  12. Effects
    1 main :: Eff _ Unit
    2 main = log "Hello world"
    3
    4 getElementById :: String → Eff _ (Maybe Element)
    5 getElementById s
    6 = ( querySelector (QuerySelector s)
    7 <<< htmlDocumentToParentNode
    8 <=< document
    9 ) =<< window
    10
    11 window :: Eff _ Window
    12 document :: Window -> Eff _ HTMLDocument
    13 htmlDocumentToParentNode :: HTMLDocument → ParentNode
    14 querySelector :: QuerySelector
    15 → ParentNode
    16 → Eff _ (Maybe Element)
    9

    View Slide

  13. Foreign Function Interface
    ParentNode.js
    1 exports._querySelector = function (selector) {
    2 return function (node) {
    3 return function () {
    4 return node.querySelector(selector);
    5 }; }; };
    ParentNode.purs
    1 foreign import _querySelector :: QuerySelector
    2 → ParentNode
    3 → Eff _ (Nullable Element)
    4
    5 querySelector :: QuerySelector
    6 → ParentNode
    7 → Eff _ (Maybe Element)
    8 querySelector qs = map toMaybe <<< _querySelector qs
    10

    View Slide

  14. My PureScript Workflow

    View Slide

  15. Tooling Demo
    • pulp init
    • pursuit
    • bower install
    • vscode
    11

    View Slide

  16. Halogen

    View Slide

  17. Basic Component
    1 data Query a = DoNothing a
    2 type Input = Unit; type Message = Void; type State = Unit
    3
    4 component :: ∀ m. H.Component HH.HTML Query Input Message m
    5 component = H.component
    6 { initialState: id
    7 , render
    8 , eval
    9 , receiver: const Nothing
    10 }
    11 where
    12
    13 render :: State → H.ComponentHTML Query
    14 render _ = HH.text "Hello, world"
    15
    16 eval :: Query H.ComponentDSL State Query Message m
    17 eval (DoNothing next) = pure next
    12

    View Slide

  18. Render
    1 render :: State → H.ComponentHTML Query
    2 render st =
    3 HH.div
    4 [ HP.class_ (H.ClassName "messages__middle") ]
    5 [ HH.div
    6 [ HP.class_ (H.ClassName "messages") ]
    7 $ (map (renderMessage st.playing) st.items)
    8 <> guard st.isSchedule
    9 [ HH.button
    10 [ HE.onClick <<< HE.input_ $ Commit
    11 , HP.class_ <<< H.ClassName $ "messages-btn"
    12 , HP.disabled $ not st.isDirty
    13 ]
    14 [ HH.text "Save" ]
    15 ]
    16 ]
    13

    View Slide

  19. Eval
    1 eval :: Query H.Component HH.HTML Query Input Message MsgM
    2 eval = case _ of
    3 Initialize next → next <$ do
    4 H.fork do
    5 env ← unMessagesEnvironment <$> H.lift ask
    6 tags → H.lift <<< liftServer $ getTags
    7 isSchedule ← H.lift $ _.isSchedule <$> get
    8 case tags of
    9 Left err → H.lift <<< navigate $ BadSetup
    10 Right t → H.put $ Just
    11 { tags: t
    12 , selectedTag: SchedOrDmd isSchedule <<< unwrap $ t
    13 , localeService: env.localeService
    14 , isSchedule: isSchedule
    15 }
    14

    View Slide

  20. Conclusion

    View Slide

  21. Resources
    • Christopher Allen, The Haskell Book http://haskellbook.com
    • Phil Freeman, PureScript by Example http://leanpub.com/pursecript
    • Pursuit, PureScript Documentation http://pursuit.purescript.org
    • Vladimir Ciobanu, Halogen Example
    http://github.com/vladciobanu/purescript-halogen-example
    • Functional Programming Slack
    https://fpchat-invite.herokuapp.com/
    • PureScript Discourse http://purescript-users.ml
    15

    View Slide

  22. We Are Hiring
    is the global leader for Experience Design services.
    The Visual Solutions is in charge of our Digital Signage product.
    We are migrating key components to Haskell and PureScript.
    Are you:
    • passionate about writing software?
    • interested in learning and use functional programming?
    If you answered yes to both questions, then you should join our team!
    No prior experience with FP is required.
    16

    View Slide

  23. Thank You
    Thank you for listening!
    cvlad
    vladciobanu
    cvlad.info
    17

    View Slide