DedSec Project

elm — consolidated language guide — DedSec Project

elm — consolidated language guide Elm The functional boundary Elm is a functional language for browser interfaces. A function transforms values without modifying a shared variable; browser…

Elm

The functional boundary

Elm is a functional language for browser interfaces. A function transforms values without modifying a shared variable; browser effects are represented separately by the Elm runtime. Before building a Model/Msg/update application, learn what a small transformation actually discards.

Save the following as src/Main.elm in a scratch project initialized with elm init:

module Main exposing (main)

import Html exposing (text)

main =
    let
        raw =
            [ "3", "oops", "4" ]

        valid =
            List.filterMap String.toInt raw
    in
    text (String.fromInt (List.sum valid))

Build with elm make src/Main.elm --output=main.js, then load the generated script from a small HTML page and initialize Elm.Main.init on a real DOM node. The displayed value should be 7. Elm dependencies may require a network connection or a populated package cache for the first build.

A subtle correctness failure

String.toInt returns Maybe Int: Just n for a parsed integer and Nothing for an invalid string. List.filterMap keeps Just values and silently discards Nothing. Therefore ["oops"] displays 0 even though no valid number was supplied. That is not a trustworthy validation strategy when every input must be accounted for.

Compare three cases: ["3", "4"] → 7; ["3", "oops", "4"] → 7 but with lost data; ["oops"] → 0. Explain why the same sum does not imply the same input quality. A production importer should return an explicit error, for example Result String (List Int), instead of dropping malformed records.

Troubleshooting and next step

If elm make reports missing elm.json, run elm init in a clean directory. If dependencies cannot be downloaded, record an environment failure rather than claiming a syntax error. If the page is blank, check browser console, generated file path and Elm.Main.init. If a type mismatch occurs, distinguish Maybe Int from Int and avoid unchecked conversion.

Exercise: implement parseAll : List String -> Result String (List Int) so the second and third test inputs fail with a useful message. Then add a Model, Msg and update to display the error in the browser. Record the Elm compiler version, build result and actual browser output. The example's outcomes are statically predicted; compiler/browser execution was not performed for this text.

Elm — Expanded practice workbook

A concrete UI boundary

Browser.sandbox can model input without a server. Store the user's raw text as String, convert only when validating, and render feedback with Html.text so the input is displayed as text rather than interpreted as markup. This is client-side feedback, not a substitute for server-side validation when data eventually crosses a network boundary.

In an elm init scratch project, save as src/Main.elm:

module Main exposing (main)

import Browser
import Html exposing (Html, div, input, label, text)
import Html.Attributes exposing (for, id, value)
import Html.Events exposing (onInput)

type alias Model =
    { raw : String }

type Msg
    = Changed String

init : Model
init =
    { raw = "" }

update : Msg -> Model -> Model
update msg model =
    case msg of
        Changed next ->
            { model | raw = next }

describe : String -> String
describe raw =
    case String.toInt raw of
        Just age ->
            if age >= 0 && age <= 120 then
                "Accepted: " ++ String.fromInt age
            else
                "Out of range"

        Nothing ->
            "Enter a whole number"

view : Model -> Html Msg
view model =
    div []
        [ label [ for "age" ] [ text "Age (0–120)" ]
        , input [ id "age", value model.raw, onInput Changed ] []
        , div [] [ text (describe model.raw) ]
        ]

main : Program () Model Msg
main =
    Browser.sandbox { init = init, update = update, view = view }

Build with elm make src/Main.elm --output=main.js and initialize Elm.Main.init with a real DOM node. An Elm compiler and dependencies are required; this workbook does not claim the build was run here.

Test matrix and rationale

Expected observations: empty text → Enter a whole number; 0 → Accepted: 0; 120 → Accepted: 120; -1 and 121 → Out of range; 12.5 and abc → Enter a whole number. String.toInt returns Maybe Int, so Nothing is handled explicitly. The boundary check is inclusive. For text such as <img src=x>, Html.text does not create an image element.

Check the visible label and its matching for/id relationship with keyboard and screen-reader inspection. Consider adding an aria-live status region and an explicit error association for a production form; merely displaying a message is not sufficient evidence of accessible error announcement.

Diagnostics, exercises and completion

A complete submission includes Elm version, code, build/browser evidence, the seven expected input cases, an accessibility observation and a deliberate failure. No browser or Elm compiler execution is asserted for this written example.

Elm — Focused mastery pathway

What the Elm Architecture separates

Elm represents state with a Model, events with a Msg union type, transitions with update and rendering with view. Browser.sandbox is suitable for this entirely local example: there are no HTTP commands or subscriptions. Unlike direct DOM mutation, the runtime renders the view from the model after each message.

In a scratch Elm project created with elm init, save the following as src/Main.elm. A working package cache or access to Elm's package registry may be needed for the first build.

module Main exposing (main)

import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)

type alias Model =
    { count : Int }

type Msg
    = Increment
    | Reset

init : Model
init =
    { count = 0 }

update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
            { model | count = model.count + 1 }

        Reset ->
            { model | count = 0 }

view : Model -> Html Msg
view model =
    div []
        [ button [ onClick Increment ] [ text "Add one" ]
        , button [ onClick Reset ] [ text "Reset" ]
        , text (String.fromInt model.count)
        ]

main : Program () Model Msg
main =
    Browser.sandbox { init = init, update = update, view = view }

Compile with elm make src/Main.elm --output=main.js. Open a disposable HTML file that loads main.js and initializes Elm.Main.init({ node: document.getElementById("app") }) on an empty div with id app. Do not inject new HTML into the same node after Elm owns it.

Predict and test

Starting from 0, clicking Add one twice must display 2; Reset returns 0. Clicking Reset immediately also yields 0. update does not modify its input record; it returns a new model. The Elm runtime handles event dispatch and DOM updates, not the update function itself.

A deliberately invalid edit, { model | count = "one" }, should be rejected because count is Int. This is a compile-time type mismatch, not a browser exception. Browser.sandbox cannot issue Cmd Msg; asynchronous HTTP requires a suitable program such as Browser.element and an explicit update result containing commands.

Troubleshooting and next level

Completion requires the compiler version, build command, browser observation for two increments and reset, a captured type-error diagnostic, and an invariant argument. The sample and outcomes are statically reasoned; no Elm runtime execution is claimed here.