Pro Yearly is on sale from $80 to $50! »

PureScript & Halogen

PureScript & Halogen

0286822f506fc4621bd3ea0bcbfef238?s=128

Bucharest FP

May 08, 2018
Tweet

Transcript

  1. PureScript & Halogen Vladimir Ciobanu Tuesday, May 8, 2018 Development

    Lead, Visual Solutions, Mood Media Romania
  2. Overview Why Not... Introduction to PureScript My PureScript Workflow Halogen

    Conclusion 1
  3. Why Not...

  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
  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
  6. Introduction to PureScript

  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
  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
  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
  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
  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
  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
  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
  14. My PureScript Workflow

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

    • vscode 11
  16. Halogen

  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
  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
  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
  20. Conclusion

  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
  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
  23. Thank You Thank you for listening! cvlad vladciobanu cvlad.info 17