DEV Community

Ryan Haskell
Ryan Haskell

Posted on • Edited on

Elm: the jerk that took away my for-loops.

The good ole' days

The first time I ever coded was my junior year of high school.

The year was 2010, her name was Java.

System.out.println("Hello, Ryan!");
Enter fullscreen mode Exit fullscreen mode

But let's pretend her name was Javascript:

console.log('Hello, Ryan!')
Enter fullscreen mode Exit fullscreen mode

(Ah, less typing...)

Pretty soon, I found myself saying "hello" to all kinds of people.

console.log('Hello, Ryan!')
console.log('Hello, Scott!')
console.log('Hello, mom!')
Enter fullscreen mode Exit fullscreen mode

Life was easy... until it wasn't.

Feeling stupid

My pal: "Ryan- what are you doing?"

Me: "I have no idea."

My pal: "You're supposed to use a for-loop for that."

Me: "wat."

My pal:

var names = [ 'Ryan', 'Scott', 'mom' ]

for (var i = 0; i < names.length; i++) {
  var name = names[i]
  console.log('Hello, ' + name + '!')
}
Enter fullscreen mode Exit fullscreen mode

Me: "..."

Also me: "WAT."

My pal: "It's not too hard. Just make an array of strings, called "names". From there, we make a for-loop:

  1. Say var i = 0; to start the index at zero.
  2. We say i < names.length to tell the for loop when to stop looping.
  3. Then type i++ so it increments after every time it's called.

The variable i will be 0, 1, and 2. You can use it to index into your array to get the name, and then use that name variable so you don't have to duplicate the repetitive 'Hello' part."

Me: "wat."

Feeling un-stupid

The first time I met the for-loop, I had a lot of questions:

  1. "Indexing into an array?"
  2. "They start counting at 0?"
  3. "Why doesn't i++ get a semicolon?"

Copy-pasting console.log statements was easy! For loops introduced me to a lot of new concepts. After some practice, I became familiar with those concepts.

It wasn't so bad. In no time, I was using them everywhere!

Even better, I got to bring the for-loop with me everywhere I went: Java, C#, Javascript, C, C++.

For-loops were my life. And life was good!

...until I met Elm.

Feeling anti-stupid

Fast forward:

  • My name was still Ryan
  • I had a job in the city making websites.
  • I was a JS pro (or at least I could add two numbers)
function add (a, b) {
  return a + b
}
Enter fullscreen mode Exit fullscreen mode

But on a train ride home, I saw an inspirational tech talk by a guy named Evan.

He designed something to make web programming nicer for folks!

The year was 2016, and her name was Elm.

add a b = a + b
Enter fullscreen mode Exit fullscreen mode

(Ah, less typing)

The syntax was definitely spooky. It didn't look anything like JS!

But neither did HTML or CSS- and I learned those!

Just like for-loops, it took at bit of practice.

So I followed the official guide, asked questions in the #beginners Slack channel, and even started putting my commas on the left side.

[ "who"
, "have"
, "I"
, "become??"
]
Enter fullscreen mode Exit fullscreen mode

Crazy, right?

Next thing you know, this HTML template:

<!-- view.html -->
<div class="app">
  <p>Hello, Ryan!</p>
  <p>Hello, Scott!</p>
  <p>Hello, mom!</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Became this Elm function:

view =
    div [ class "app" ]
        [ p [] [ text "Hello, Ryan!" ]
        , p [] [ text "Hello, Scott!" ]
        , p [] [ text "Hello, mom!" ]
        ]
Enter fullscreen mode Exit fullscreen mode

Haha, what a breeze!

Feeling re-stupid

Wait a minute... look at all that duplication!

I know- I'll grab my trusty for-loop!

Let's hit up the Elm docs to find the function I'm looking for:

Module docs for the term

My god... Evan forgot to implement for-loops.

What a rookie mistake.

So I hopped on the Slack, to find out what to do.

A friendly Elm stranger let me know that List.map was the function I was looking for.

Me: "wat."

A friendly Elm stranger:

names =
    [ "Ryan", "Scott", "mom" ]

viewParagraph name =
    p [] [ text ("Hello, " ++ name ++ "!") ]

view =
    div [] (List.map viewParagraph names)
Enter fullscreen mode Exit fullscreen mode

Me: "wat."

A friendly Elm stranger: "lol, noob"

(Just kidding, I've never been called a noob on the Elm slack)

A friendly Elm stranger: "Let's break it down a bit.

List.map is just a function, like view or viewParagraph.

It takes in two inputs:

  1. A function that turns "things" into "other things"

  2. A list of "things".

If you give it those inputs, it'll return back a list of "other things".

List.map : (things -> otherThings) -> List things -> List otherThings
Enter fullscreen mode Exit fullscreen mode

In your example, you had a list of "strings" you wanted to turn into a list of "HTML".

So your "things" are "Strings", and your "other things" are "HTML"!

List.map : (String -> Html msg) -> List String -> List (Html msg)
Enter fullscreen mode Exit fullscreen mode

Just tell List.map how to turn a "string" into "HTML elements" (viewParagraph), and give it your list of "strings" (names).

You'll get back your list of "HTML", and that's what you can print to the page."

Me: "..."

Also me: "I'm scared."

Feeling un-re-stupid

After I got some practice with List.map, I started getting the hang of it.

Soon afterwards, I found out JavaScript has the map function too!

And it's been there for a long time!

function sayHello (name) {
  console.log('Hello, ' + name + '!')
}

[ 'Ryan', 'Scott', 'mom' ].map(sayHello)
Enter fullscreen mode Exit fullscreen mode

Elm forced me to use their weird loop thing.

I felt tricked! But then I liked it better.

Now I only use for-loops in blog posts.

So thanks, Evan.

I'm glad you forgot the for-loop.

Also your talk was pretty dope.

Thanks for reading! ❤️

Top comments (10)

Collapse
 
drbearhands profile image
DrBearhands

At the risk of earning myself a major woosh:

JS is a language of actions. It does things: "allocating" a variable and changing its value are the building blocks of a for loop.

Elm is a language of definitions. One list (of html elements) is a transformation of another list (in this case the function was constructed using map).

The compiler turns Elm's declarations into commands that can actually be executed.

So JS's map function is not the same as Elm's map function. It is just a more specific form of a for loop with some restrictions.

Collapse
 
1hko profile image
1hko • Edited

I disagree with this. JS is a multi-paradigm language where multiple disciplines can be used. JavaScript includes first-class functions, destructuring assignment, and other features which enable great support for functional style. You can avoid many object-oriented or imperative-style features of the language and skip all the headaches that come with them.

Collapse
 
ryan-haskell profile image
Ryan Haskell

I totally agree with you!

The point of the post was not to say "JavaScript doesn't support functional programming"

It was just about my experience with a language that only supported functional things.

When I first got started with JS, I naturally used for loops because of my background with Java and imperative languages.

Elm forced me to try something different, and now that's the style I prefer using in JS too 😃

Thanks for your reply, sorry about causing the confusion!

Collapse
 
drbearhands profile image
DrBearhands

I never said anything about functional style so I'm not sure what you're trying to disagree with here...

Thread Thread
 
1hko profile image
1hko

JS is a language of actions. It does things: "allocating" a variable and changing its value are the building blocks of a for loop.

I politely disagree with your summary of what JS is, that's all.

Thread Thread
 
ryan-haskell profile image
Ryan Haskell

Oh sorry, that wasn't my quote 😅

Thought this was a direct reply to my article haha

Thread Thread
 
drbearhands profile image
DrBearhands

"Functional style", ill-defined as it is, does not equate to not having effects / actions.

Collapse
 
ryan-haskell profile image
Ryan Haskell

That's a really interesting perspective, thanks for sharing it!

I never thought about it that way 😀

Collapse
 
drbearhands profile image
DrBearhands

If you want to understand more about it, Bartosz Milewski has a great series about the underlying theory. First two chapters should give you a pretty good idea of what's going on.

Collapse
 
1hko profile image
1hko • Edited

List.map isn't the only way to "loop" in Elm. Recursion is the construct for repeating something in a functional language. If map didn't exist, you could easily write it on your own using recursion -

map : (a -> b) -> List a -> List b
map f list =
    case list of
        [] -> []
        first :: more -> (f first) :: map f more

> map (\n -> n * n) [ 1, 2, 3, 4 ]
-- [ 1, 4, 9, 16 ] : number

> map (\n -> String.repeat n "x") [ 1, 2, 3, 4 ]
-- [ "x", "xx", "xxx", "xxxx" ] : List String

This goes for any program where a "loop" is needed. In some procedural language, you might write the classic fibonacci program -

function fibonacci (n = 0) {
  let a = 0, b = 1, temp
  for (let m = 0; m < n; m++) {
    temp = a
    a = b
    b = temp + b
  }
  return a
}

> fibonacci(10)
// 55

> fibonacci(50)
// 12586269025

But in a functional language like Elm, we use recursion and avoid side-effects like variable mutation and reassignment. The result is a program that is much easier to think about -

fibonacci : Int -> Int
fibonacci n =
    helper n 0 1

helper : Int -> Int -> Int -> Int
helper n a b =
    case n of
        0 -> a
        _ -> helper (n - 1) b (a + b)

> fibonacci 10
-- 55 : Int

> fibonacci 50
-- 12586269025 : Int