Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Static in the Front, Dynamic in the Back

Static in the Front, Dynamic in the Back

An exploration of the benefits of the Elm language, how development style changes when using it, and what learnings you can bring back with you to JavaScript, React, or other libraries.

Matt Machuga

November 10, 2023
Tweet

More Decks by Matt Machuga

Other Decks in Programming

Transcript

  1. Functions in PHP function double($x) { return $x * 2;

    } function($x) { return $x * 2; }
  2. Elm • Purely functional language • Browser-based - compiles to

    JS • ML family - Standard ML and Haskell inspired • DO NOT LEAVE, PLEASE • Haskell on easy-mode • No runtime errors - no ‘unde fi ned’ is not a function
  3. Functions in Elm msgTo : String -> String -> String


    msgTo name msg = msg ++ “ to “ ++ name
  4. Functions in Elm • Statically typed • Pure (free from

    side-effects) • Only take one argument (technically) • Automatically curried • Have multi-argument syntax sugar • Implicitly return last value
  5. Equivalent in JS const msgTo = function(name, msg = "")

    { const msgFn = msg => msg + " to " + name; if (msg) { return msgFn(msg); } else { return msgFn; } };
  6. Equivalent in PHP $msgTo = function(string $name, string $msg =

    "") { $msgFn = function(string $msg) use ($name) { return $msg . " to " . $name; }; if ($msg) { return $msgFn($msg); } else { return $msgFn; } };
  7. Mapping over Lists • Apply a function to each element

    • Return new list of transformed elements, 1-to-1
  8. Mapping over Lists array_map(function($el) {
 return $el * 2;
 },

    [1,2,3,4,5]); # => [2,4,6,8,10] List.map (\el -> el * 2) [1,2,3,4,5] -- [2,4,6,8,10]
  9. Mapping over Lists $double = function($el) { return $el *

    2; } array_map($double, [1,2,3,4,5]); # => [2,4,6,8,10] double = \el -> el * 2 List.map double [1,2,3,4,5] -- [2,4,6,8,10]
  10. Mapping over Lists $double = function($el) { return $el *

    2; } array_map($double, [1,2,3,4,5]); # => [2,4,6,8,10] double el = el * 2 List.map double [1,2,3,4,5] -- [2,4,6,8,10]
  11. GitHub Issues Viewer • Enter a GitHub repo to view

    a list of its issues • Show: • Title • Body • Url • Comment count • Labels
  12. q

  13. elm-format • Atom ran code through elm-format • Saw we

    were missing module declaration • Added module declaration as name of fi le • Formatted code
  14. elm-make The `main` value has an unsupported type. I need

    Html, Svg, or a Program so I have something to render on screen, but you gave me: String
  15. elm-make The `main` value has an unsupported type. I need

    Html, Svg, or a Program so I have something to render on screen, but you gave me: String
  16. Warning Top-level value `main` does not have a type annotation.

    I inferred the type annotation so you can copy it into your code: main : Html msg
  17. What is `Html msg`? • Main returns with the type

    `Html msg` • Means it is a chunk of Html that can produce values of any type. • Ignore this for now
  18. Loading Elm in App <!-- Element to inject app into

    -->
 <div id="app"></div> <!-- Load compiled elm app + runtime -->
 <script src="elm.js"></script> <!-- Embed Elm app into element -->
 <script>
 Elm.Main.embed(
 document.getElementById("app")
 );
 </script>
  19. Convert HTML <form class="form"> <div class="form-group"> <div class="row"> <div class="col-md-8">

    <input type="text" class="input-lg form-control" placeholder="Enter a GitHub Repo (Ex: elm-lang/elm)"/> </div> <div class="col-md-4"> <input type="submit" class="btn btn-primary btn-lg" value="Load Issues" /> </div> </div> </div> </form>
  20. To Elm inputView = form [ class "form" ] [

    div [ class "form-group" ] [ div [ class "row" ] [ div [ class "col-md-8" ] [ input [ type_ "text" , class "input-lg form-control" , placeholder "Enter a GitHub Repo (Ex: elm-lang/elm)" ] [] ] , div [ class "col-md-4" ] [ input [ type_ "submit" , class "btn btn-primary btn-lg" , value "Load Issues" ] [] ] ] ] ]
  21. Html Element Signature div : List (Html.Attribute msg) 
 ->

    List (Html.Html msg)
 -> Html.Html msg -- div takes a List of Attributes
 -- and a List of child Html Elements
 -- and returns an Html Element
  22. Html Element Signature inputView = form [ class "form" ]

    [ div [ class "form-group" ] [ div [ class "row" ] [ div [ class "col-md-8" ] [ input [ type_ "text" , class "input-lg form-control" , placeholder "Enter a GitHub Repo (Ex: elm-lang/elm)" ] [] ] , div [ class "col-md-4" ] [ input [ type_ "submit" , class "btn btn-primary btn-lg" , value "Load Issues" ] [] ] ] ] ]
  23. Html Element Signature inputView = form [ class "form" ]

    [ div [ class "form-group" ] [ div [ class "row" ] [ div [ class "col-md-8" ] [ input [ type_ "text" , class "input-lg form-control" , placeholder "Enter a GitHub Repo (Ex: elm-lang/elm)" ] [] ] , div [ class "col-md-4" ] [ input [ type_ "submit" , class "btn btn-primary btn-lg" , value "Load Issues" ] [] ] ] ] ]
  24. 2

  25. type alias • Create a domain-speci fi c type •

    Composable of other types • “Alias this structure by this name” • Keep type signatures clean
  26. type alias Model type alias Model = { repo :

    String , issues : List GitHubIssue }
  27. Recall from earlier • We want our issues to show:

    • Title • Body • Url • Comment count • Labels
  28. type alias GitHubIssue type alias GitHubIssue = { title :

    String , body : String , url : String , comments : Int , labels : List GitHubLabel }
  29. What do we have? • List containing n-number of issues

    • HTML element that takes a list of child elements
  30. More guidance The 1st argument to function `map` is causing

    a mismatch. Function `map` is expecting the 1st argument to be: a -> VirtualDom.Node msg But it is: Html msg It looks like a function needs 1 more argument.
  31. Type Mismatch Function `map` is expecting the 1st argument to

    be: a -> VirtualDom.Node msg But it is: Html msg It looks like a function needs 1 more argument.
  32. Html.program main = Html.program { init : (Model, Cmd msg)

    , view : Model -> Html msg , update : msg -> Model -> (Model, Cmd msg) , subscriptions : Model -> Sub msg }
  33. type - Union Types • A type to represent complex

    data • A type to represent acceptable types
  34. Example from Elm Docs type User = Named String |

    Anonymous activeUsers : List User
 activeUsers = 
 [ Anonymous, Named “Machuga”]
  35. case...of update : msg -> Model -> ( Model, Cmd

    msg )
 update msg model =
 init
  36. case...of update : Msg -> Model -> ( Model, Cmd

    msg )
 update msg model =
 init
  37. case...of update : Msg -> Model -> ( Model, Cmd

    msg )
 update msg model = case msg of SetRepo repo -> ....
  38. Type Mismatch The de fi nition of `main` does not

    match its type annotation. The type annotation for `main` says it is a: Program Never Model msg But the de fi nition (shown above) is a: Program Never Model Msg Your type annotation uses type variable `msg` which means any type of value can fl ow through. Your code is saying it CANNOT be anything though! Maybe change your type annotation to be more speci fi c? Maybe the code has a problem? More at: <https://github.com/elm-lang/elm-compiler/blob/0.18.0/hints/type-annotations.md>
  39. Determinism This `case` does not have branches for all possibilities.

    You need to account for the following values: Main.FetchIssues Add a branch to cover this pattern! If you are seeing this error for the fi rst time, check out these hints: https://github.com/elm-lang/elm-compiler/blob/0.18.0/hints/missing-patterns.md The recommendations about wildcard patterns and `Debug.crash` are important!
  40. Updating a Record { model | key = value }

    -- Read as: -- Model, such that key is equal to value
  41. Maybe type Maybe = Just a | Nothing -- Maybe

    String says: -- The value is either just a string -- or it is nothing -- Developer must account for both
  42. Warning: Boss Fight If we made it this far, I’m

    shocked, and you’re awesome!
  43. Add More Functionality type Msg = SetRepo String | FetchIssues

    | LoadIssues (Result Http.Error (List GitHubIssue))
  44. What? LoadIssues (Result Http.Error (List GitHubIssue)) -- LoadIssues takes --

    a Result that will return either -- Http.Error -- List GitHubIssue
  45. Whoa -- Construct the get, pass to send, the result

    will be sent to LoadIssues Http.send 
 LoadIssues <| Http.get (repoUrl repo) (Decode.list issueDecoder)