Elm Guide - small edit suggestion

Seriously studying Elm for the first time and going through the Elm-Guide.
So far (just finished the Pattern Matching chapter) I love it! :smiley:

But… as a non-programmer that is trying to learn his first language I REALLY would have appreciated if the order of topics was:

  • Introduction
  • Install
  • Core Language
  • The Elm Architecture
    – Buttons
    – Text Fields
    – Forms (without the final button exercise)
  • Types
    – Reading Types
    – Type Aliases
    – Custom Types
    – Pattern Matching
    – Forms (refactoring + final button exercise)

Instead I had to pretty much look for third party solutions of the problem, copy them, try to understand them, and call it a day. I would have much preferred to be put in the condition of solving the problem on my own.
Still, it’s all learning :slight_smile:

Can you explain why was this order more intuitive to you?

I think it would be great to have a guide or tutorial like “Elm as a first language”. Are you interested in doing something like this? You could start with a blogpost

Not sure how to go about blogging about code, but I surely can try to write an actual play of my experience :slight_smile:

So I have little to no coding experience. I attended a professional course about HTML and CSS and Javascript, but it was 20 years ago, and I never really put it into practice. Since then I periodically try to teach myself coding of some kind, but never got anywhere, and eventually let go.
I tried dipping my toes in Elm in the past two years, but never really sat down methodically going through the Guide.
Now I’m finally getting around to it :slight_smile:


Pretty much everything up to the final part of the Form exercise felt well paced.
The Guide offers examples, and goes about explaining them bit by bit. It’s very clear and friendly.

In the Form exercise I remember how checking for length and digit/upper/lower characters was not too much of a problem.

I had to think on my own and go search the Elm Package pages.
The Guide points the reader towards the String package… which is ok for the length function.
But then I had to go looking for other functions in the Char package. A small pitfall here was that the any function uses isDigit as an example… and I thought it was a whole thing within the String package, not a separate function from another package.
This resulted in an error that told me to check how import works … but my “import String” syntax seemed correct! :thinking:
There I first searched for some external solution, a way to check for upper/lower case, and Google returned me stuff that led me to the Char package. The world was right again.

Another (doable) challenge was to actually understand how to implement in my code the functions described in the Package pages. Here the compiler and some trial and error did the trick.

In the end I had a clunky bunch of separate function, each performing one of the required checks, all invoked en masse at the end of the example View function. Horrible, but it worked :stuck_out_tongue_winking_eye:

And then the last bit came along: make a button that performs these checks, and do them only when the button is clicked.
This felt much more difficult to do.
I felt kind of lost.

I started by adding the new button to the View, and then got stumped.
It did not immediately occur to me that a new button meant “a new action” and thus a new entry in the Update function. And consequently it did not occur to me to modify the Model to handle this.

After peeking at someone else’s solution I felt possibly even more confused.
On the one hand I saw what I was supposed to do.
On the other hand the implementation looked alien, far more advanced than what I knew how to code, more abstract than I knew how to think.
Still, it was something I could try to understand and use.

I refused to just copy the code and tried to only peek at it as an example to type my own code. But I kept failing. The compiler helped a bit, but not enough for me to understand what was wrong or missing.
I don’t remember every detail now, but mainly I felt like I was not really understanding how to use/write the type annotations (thus what was supposed to go in a function and come out of it), and what actually a Type meant for the program (thus how and why to create new ones, add stuff into their definition, etc).

Eventually I stumbled upon THIS solution which was both well explained AND followed a logic that I felt more familiar to me. I was imagining a solution, and this implementation matched closely enough my own reasoning.
It still had foreign elements (the Let function, which is nicely described in the Syntax but not mentioned in the Guide up to this point) but it was understandable enough.

This led me to finally code what the exercise required. The whole process took me two afternoons :stuck_out_tongue:

And then I went on the next step of the Guide, and it was a constant “ooooh that’s it!”.
Reading the Types chapter explained SO MANY THING that felt weird and obscure before, both regarding Types themselves, but also about Functions, their structure, refactoring, etc.

Maybe it’s just an impression post facto, but I think that if I had read this stuff before the submit-button exercise I would have had an easier time.

Another thing I’ve noticed, both about the Guide and other tutorials I’ve skimmed online… they ALL seem to follow a top-to-bottom train of thought.
Submit Button? Sure, first of all think about your Model, than use it to expand the Update, and finally plug that into your View.

I seem to struggle with this logic, and tend to proceed in a bottom-to-top direction.
Submit Button? Well it’s a button right? So I do my button in the view. But what does it do? I guess it does some action… which means something should happen in the Update. Let’s go expand it to accomodate. Mmm, to make this update action the way I imagine it I need to store a new value somewhere. Where do I do this? In the Model! (this was actually a not obvious realization for me) Time to change the Model too then!

Going the other way around I found myself lost. So… the Model first… what am I supposed to do with it? I don’t know. It’s unclear. The mind reels at the possibilities :stuck_out_tongue:
Is there a cure for this? XD
Or can this way of thinking be correct too?

4 Likes

Thanks for sharing your experience of getting used to Elm. I am sure many of the stumbling blocks and strategies you have adopted will chime with many others, not just in Elm but in learning any new language.

One of the challenges in producing a definitive guide to Elm (or any language) is that what works for one person might not be right for another. Prior experience, motivation for learning, the types of applications you are looking to build and no doubt many other factors will influence what you prefer. So it is inevitable that any single guide will not always be structured in the way any one of us might hope. The key is being able to access a range of support materials so that you can select the one(s) that best matches what you need.

In my case, I was drawn to Elm because I wanted to understand more about what a ‘functional approach’ actually meant in practice and had heard it was designed deliberately to support beginners get on board with the functional way of thinking. As such, I was less interested (at first anyway) in the Elm Architecture (Models, View, Update etc.) and more about how to use the language itself. Obviously, this may not be your motivation, but I did find it very useful to understand the language before looking in any great detail at the examples in the Elm-Guide. Doing so meant that when I saw the letters Cmd in the guide, I wasn’t continually asking myself, "Is that a function?; a type? a type variable? a variable? etc. Or when I knew I needed to do something with every element in a list, I knew where to start. I think it reduced the amount of trial and error required to get things working.

If the approach of getting to grips with the language first, before using it to build apps appeals, you may wish to consider some or all of the following:

  • Exercism Graded exercises with friendly peer support in Elm (and 41 other languages!)
  • 99 Problems in Elm More graded exercises with hints and solutions focussing on basic computational ideas such as list processing, logic and data structures.
  • An Outsider’s Guide to Statically Typed Functional Programming by Brian Marick. Don’t be put off by the slightly technical title - this is a great, accessible and pragmatic introduction to the functional way of doing things, largely illustrated with Elm.
  • Advent of Code This isn’t Elm-specific, but a fun collection of programming challenges (new ones released every December) and an active community of ‘contestants’ every December who discuss approaches on reddit. There are a few of us who have been using Elm to tackle the problems, and I would particularly recommend @Janiczek live coding videos to see Elm being written in situ (at 5am!) . (And should you catch the Advent of Code bug, you can see my own Elm solutions).
1 Like

What about a “choose your own adventure” style guide? I’m imagining a setup where each section is prefaced with a question about how comfortable the reader feels with a given concept and their answer determines the nature of the content for that section. So someone who responds “very comfortable” gets a Reader’s Digest overview of the Elm-specific syntax while one who responds “not at all comfortable” gets a step-by-step walk through of the concept. Given the guide lives electronically, it does not need to be constrained by physical book idioms. Sort of similar to Scott McCloud’s thoughts on digital storytelling in comics (http://scottmccloud.com/1-webcomics/icst/icst-4/icst-4.html).

1 Like

I was trying to personalize a bit the page resulting from the Form exercise … using Elm-UI.
Unfortunately it’s not as intuitive as I hoped >__<
I thought I would just need to import the package and use the Elements in place of the Html divs and stuff like that… but it seems to require MUCH more messing around than that, and I’m getting lost :stuck_out_tongue:

Any suggestions on where to learn how to use it without spending ages fumbling with every single element of that package? :slight_smile:

That’s probably the best place to start example wise. I don’t know of a tutorial or guide that walks through elm-ui forms as of yet.

Thanks a lot!
I’ll look into it :smiley:

Sooo… struggling through the example, I’m stuck trying to make a text-field to input a username.
The package documentation looks like this:

username :
List (Attribute msg)
->
{ onChange : String -> msg
, text : String
, placeholder : Maybe (Placeholder msg)
, label : Label msg
}
-> Element msg


I’m not sure I understand correctly (even looking at the mcGriffith example, which is VERY helpful anyway) all the things the package puts into the Username element.
Especially the onChange one.
I was trying to create a text field and then call a function to update the model.

–MODEL
type alias Form =
{ name : String
, age : String
, password : String
, passwordAgain : String
, validity : Bool
}

init : Form
init =
{ name = “”
, age = “”
, password = “”
, passwordAgain = “”
, validity = False
}

–UPDATE

type Msg
= Name String
| Age String
| Password String
| PasswordAgain String
| Validate

update : Msg → Form → Form
update msg form =
case msg of
Name name →
{ form | name = name, validity = False }

    Age age ->
        { form | age = age, validity = False }

    Password password ->
        { form | password = password, validity = False }

    PasswordAgain password ->
        { form | passwordAgain = password, validity = False }

    Validate ->
        { form | validity = True }

–VIEW

view form =
Element.layout <|
Element.column [ centerX, centerY ]
[ el (text “My Simple Form”)
, Input.username
{ text = form.name
, placeholder = Just (Input.placeholder (text “username”))
, onChange = ???
, label = Element.none
}
]

The mcGriffith example seems to skip the Update function and instead use an in-line unnamed function to update the Model.
Is this mandatory?
Can’t I use an external Update function like the one in my code?
I tried… but I get all kinds of errors :confused:

Let’s see…
text shows the content of the model, which is initialised as empty.
placeholder fills the text-box with a placeholder text provided here (why is it so complicated? in the HTML module you just write placeholder “text” … am I doing something wrong?
label is … for accessibility? code maintenance?

And finally there is onChange.
In the docs onChange takes a String and returns some msg variable (that’s what msg is for, right? or is it descriptive of a specific kind of variable?).
So… am I forced to put a function in here?

I tried passing it

, onChange = update Name name

but the compiler says that “name” is an unknown variable x_x

In the example mdgriffith has defined only a single Msg:

type Msg
    = Update Form

and the anonymous function for onChange sends the Update variant of Msg. The password field of the form for instance uses this:

onChange = \new -> Update { model | password = new }

In this case the model is a Form type and the current model is being copied to the new model with a change to the password field.
The actual update function is:

update msg model =
    case Debug.log "msg" msg of
        Update new ->
            new

which just returns the new model to re-render the view (or at least the parts that need to be re-rendered).
This is nice efficient code, but you could re-write it a little more explicitly by having a Msg type for each field, which might be more human readable for you.

type alias Form =
    { username : String
    , password : String
    , agreeTOS : Bool
    , comment : String
    , lunch : Lunch
    , spiciness : Float
    }


type Msg
    = UpdateName String
    , UpdatePassword String
    , UpdateAgreeTOS bool
    , UpdateComment String
    , UpdateLunch Lunch
    , UpdateSpiciness Float

...

update msg model =
    case msg of
        UpdateName new -> { model | username = new }
        UpdatePassword new -> { model | password = new }
        UpdateAgreeTOS new -> { model | agreeTOS = new }
        UpdateComment new -> { model | comment = new }
        UpdateLunch new -> { model | lunch = new }
        UpdateSpiciness new -> { model | spiciness = new }

Now anywhere you need onChange you just send the Msg variant that is appropriate to the field. For the password field, for example:

onChange = \textInput -> UpdatePassword textInput

The update function will take that Msg and apply it to the model and return the new model to the view. Hope this helps. If you want additional help, I would suggest starting a new thread as this is somewhat off topic for this thread.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.