Using While Loops in Elixir

While loops are my God given right!Dealing with StateHere’s the hard truth.

State happens.

To prove it, I’ve written a stoplight server.

This is a simple GenServer that updates it’s internal traffic light state every millisecond (I’m told this is how it works in Los Angeles).

We’re also given a check_light function to view the state at any time.

Now, if I want to consume this information, I'll need to interact with a stateful world.

I've also written a bit of self driving car software that interacts with the stoplight server.

Like Elon, I've decided to open source my code for an autonomous vehicle.

You're welcome mankind.

This will repeatedly check the stoplight to see if it’s green.

If it is not green, it will tell you to wait (yes, even on yellow lights you freewheelin’ maniac).

Simple stuff.

The kind of stuff that seems perfect for a while loop, so I’m going to use one.

Let’s try writing us an old fashioned while function.

We created a function that will check a given value, and if true, will perform the given function recursively until that value isn’t true anymore.

But running this against our stateful server will highlight a problem.

Our loop will either continue forever, or finish immediately.

The stateful expression is computed before being passed into the function.

The check_light function is only called once on the initial while invocation.

If we want to re-evaluate the predicate on every iteration, we'll have to wrap it inside yet another function.

But I think we're starting to stray too far from the while loop I want.

Lets crank the volume up to 11 and utilize some macros.

A Macro WhileNow most people will tell you not to use macros unless absolutely necessary.

And I’m going to have to agree with most people here.

But this is absolutely necessary, nothing gets between me and my while loops.

Here’s while written as a macro.

This does some pretty gnarly stuff.

We define an anonymous recursive function, which accepts a function that will be called if the predicate evaluates to true.

After defining this function, we pass it into itself.

This is just a trick to create a recursive function while avoiding the def keyword, allowing us to call our while outside of a module definition.

Despite all this ugliness, we actually get a pretty slick interface.

This is almost perfect, but the syntax isn’t quite right.

While.

while?.This ain’t the while while west.

I just want a plain and simple, no frills while loop.

I also want the title of this post to be clever, so we're going to use the __using__ keyword.

When a module uses use with another module, it will immediately call the __using__ callback from the module being used.

We're going to use this to define a macro in the Car module.

Have I used the word "use" enough in this paragraph?.I need the SEO points.

And there you have it!.When the Car module is compiled, it will call the __using__ macro, which defines it's own while macro inside of Car.

And now we can call while straight from our Car module.

Closing ThoughtsEven after all this, we’re still using recursion.

We just gave it an unnecessary paint job.

You don’t need while loops.

Use recursion, it's cleaner and more fun.

Originally published at https://codingwithalchemy.

com on May 4, 2019.

.

. More details

Leave a Reply