This course has been updated! We now recommend you take the Introduction to Elm, v2 course.
Table of Contents
The Elm Language
Why bother?Richard explores the motive for choosing to code in Elm and show some advantages—such as the Elm compiler catches errors and suggests remedies.
HTML and the virtual DOMElm comment syntax and HTML elements are shown as functions. He answers a question on Elm vs. TypeScript.
Exercise 1The first exercise is to resolve the ToDo’s in the code provided. We’re building an application similar to GitHub but for Elm repos.
Exercise 1 SolutionWe add some HTML elements into the Main.elm application.
Basic Data StructuresRichard talks about basic data structures in Elm such as strings, let expressions, records, tuples, and lists.
CollectionsRichard discusses destructuring the data structures.
Exercise 2The second exercise is to display the results of a search.
Exercise 2 SolutionThe search results are displayed and formatted with data destructured from the model.
BooleansThe Boolean datatype and operators are shown.
Partial ApplicationRichard explores partial function application. Partial function application means that a function can be called with fewer arguments than expected, also known as currying.
List.filter and List.mapThe List methods filter and map are presented.
The Elm ArchitectureRichard introduces the Elm architecture of model, view, and update. All of the application state lives in the model. When the update function changes the model, the view function returns the Html record and then the Elm runtime renders that as HTML.
InteractivityUser interaction handlers send messages to the update function which creates a new model. That new model gets passed to view and view sends a new Html record to the Elm runtime.
Exercise 3The third exercise adds delete functionality to the search results.
Exercise 3 SolutionThe solution is to add a delete message to update that creates a new model by using filter.
Type AnnotationsType annotations are optional but if declared the compiler will enforce them. You can create type aliases to compound type annotations.
Function AnnotationsFunction arguments and returns can also have type annotations that are enforced by the compiler.
Exercise 4The fourth exercises involves improving documentation by adding type aliases.
Exercise 4 SolutionType annotations are added to variables, functions, and type aliases.
Case ExpressionsCase expressions are presented as more concise than if-then-else.
Union TypesYou can declare custom types. Union types can be compounds of values, constants, and functions
MessagesMessages are shown as type aliases. A case expression is used to parse the message.
Exercise 5The fifth exercise grabs a string from a text field to set the model’s query field. The second task is to add a delete by ID message
Questions: FunctionsRichard answers questions about functions without bodies. He discusses uppercase and lowercase function names.
Exercise 5 SolutionRichard writes code to grab a string from a text field and add it to a message using OnInput. He uses an OnClick handler to delete a result.
Questions: Functions & Messages UpdateRichard answers a question about when functions are executed and the flow of messages and the Update function.
Result and MaybeBuilt-in functions return a union type that contains two values, Ok and Err. It’s necessary to use a case expression to parse the union to get the value. The Maybe type has at most one value.
PipelinesPipeline style allows an expression to be coded on multiple lines separated by pipes. Each line takes as it’s argument the value returned from previous line.
DecodersDecoders are functions that accept JSON data as an argument and return a value. A decoder can be composed of multiple decoders arranged pipeline style.
Questions: Decoder & RefactoringRichard explains that decoders make for easier refactoring.
Exercise 6The sixth exercise involves building a decoder for search results.
Questions: Decode Identity & NamingRichard answers questions about decode identity and function name uppercase.
Exercise 6 SolutionRichard builds out the case expression that accepts the search results.Then he completes the pipe that decodes the search results.
Questions: Logging, Types, Pipeline Decoding, etcRichards answers questions about logging inside a case expression, having multiple expressions inside a case branch, uppercase for type annotations, pipeline decoding, debug.log, let expressions, and virtual DOM.
Function GuaranteesFunctions in Elm are pure. If you give functions the same arguments they will always return the same value. It’s impossible for Elm to have a function that generates a random number. To get a random number from Elm you must use a command.
Another Function GuaranteeElm functions do not perform side effects. Functions do not modify external state. Commands may modify external state. Tasks may also modify state.
HTTP GETHttp.get takes as arguments a decoder and a URL.
Exercise 7The seventh exercise involves commands and tasks to work with the search results.
Exercise 7 SolutionRichard creates a task that converts into a command that decodes the search results and handles the error.
Day One Wrap UpRichards presents some links to Elm resources and talks about his book.
Questions: Imports, Subscriptions, Perf, etcRichard answers questions about imports, graphQL, subscriptions, reordering a list, virtual DOM, performance, server-side Elm, concurrency, Elm for native mobile applications, and server-side rendering.
SubscriptionsSubscriptions manage messages from outside Elm.
Receiving ResponsesRichard discusses how Elm listens for responses.
Questions: Events, Handlers, Ports, etcRichard answers questions about listening for window events and web sockets. A question is asked about click handlers and other event handlers. Ports manage communications asynchronously.
Exercise 8The eight exercise asks the user to complete the port code and implement decoders. Richard answers questions about subscriptions and ports, and getting DOM properties.
Exercise 8 SolutionRichard hooks up the ports and logic for receiving the search results.
Questions: Memoize JSON, Caching, Error TypesRichard answers questions about memoizing JSON requests and caching server responses. He talks about error types.
The Elm PackageThe elm-pack.json file is explored.
Testing SetupThe tests directory with it’s own elm-pack.json is explored, showing dependencies on test runners. Richard answers questions about npm.
TestingYou can search the package manager for packages by type. Unit tests are shown in Elm and compared to Mocha and Jasmine.
Fuzz TestingFuzz testing allows for randomly generated arguments for functions. Richards answers questions about custom fuzzers.
Exercise 9The ninth exercise asks the user to create a unit test and a fuzz test.
Exercise 9 SolutionRichard completes the todos and resolves the errors revealed by the tests. He answers questions about debouncing, and task versus command.
Delegation IntroductionRefactoring with delegation is introduced as a technique to be able to scale your application and organize your code.
Building SearchThe search options are scoped from the model with map functions.
Exercise 10The tenth exercise asks you to use delegation to refactor the search options in the model and the view. Richard answers questions about organizing your modules, accessing the model from the view options, and module size.
Exercise 10 SolutionA new constructor function is added for the search options and the view options. Richard shows how a helper function to destructure the model may complicate your code.
Scaling Elm Code
Unidirectional Data FlowRichard explains how to solve the deeply nested component problem with the Elm architecture.
Scaling FundamentalsExpand and refactor to scale your code. Richard answers a question about using Elm and React together, and also using multiple Elm apps, and multiple Elm app communication using ports.
Scaling ExamplesOne way to scale the viewer the model, or update is to split into smaller helper functions.
Portable Signup FormRichard discusses approaches to creating a reusable signup form with validation.
Exercise 11Exercise 11 involves using a sortable table component.
Exercise 11 SolutionThe tasks to be completed are add table state to the model, initialize the state, add a new message, change the update function to receive the new message, and configure the table with the table state, and add it to the view. Richard shows another component as an example—autocomplete.
CompositionRichard show various ways to write functions to access fields.
List PerformanceList performance techniques are explained by examining the underlying data structures.
Rendering PerformanceRendering performance is improved by skipping DOM building using the lazy function.
RequestAnimationFrameRestricting the view function to repaint no faster than the browser repaints is built into Elm.
Exercise 12Exercise 12 involves using debug.log and lazy.
Exercise 12 SolutionThe solution adds lazy to the search results.
ToolsThe first tool accepts HTML and returns Elm Html. The second tool accepts JSON and returns Elm type alias and decoders and encoders. The third tool lists compiler error messages. The fourth tool generates boilerplate Elm application code. The fifth tool is a pretty print for Elm code. The sixth tool is built into the latest version of ELM and is a history of messages that map to each change of application state. The seventh tool lets you define your CSS in Elm.
Elm-cssRichard mentions the last exercise of using elm-css.
Links of InterestLinks of interest.