2017, the year after the Brazil’s democracy death, was one of my more fruitful years (the more at all was 2008), so I decided to transcript some of that year’s posts back.
I’m starting with a compilation of two posts¹ ² about interators in MoonScript.
The Lua’s standard approach is a function that returns multiple values:
nil
if it’s ended.For instance, the Collatz Conjecture can be implemented as follows:
collatz = => _collatz, 1, @*2
The initial value is dobled to allow the first step to return it; the loop ends
when the state reaches one (1
).
The deal function (_collatz
) must accept the stop condition (1
) and the
last value. Using the MoonScript’s self
, we can omit the first argument:
_collatz = (last) =>
return if last == @
switch last % 2
when 0
last / 2
when 1
last * 3 + 1
Then it already works in mooni
:
moon> print x for x in collatz 10
10
5
16
8
4
2
1
moon>
We can solve this problem by using closures too.
For that, we need to write a factory that returns only the deal function, but with no arguments.
collatz = (value) ->
value *= 2
->
return if value == 1
switch value % 2
when 0
value /= 2
when 1
value = value * 3 + 1
value
This new function holding a closure (the value
variable) behaves exactly like
the collatz
implemented using the standard iterator, but in one single block.
The more powerful resource in Lua is the coroutine.
Coroutines allow yielding results while it keeps running the concurrent routine.
Collatz Conjecture using coroutine is:
_collatz = (value using coroutine) ->
import wrap, yield from coroutine
wrap ->
while value != 1
yield value
switch value % 2
when 0
value /= 2
when 1
value = value * 3 + 1
1
And also:
moon> print x for x in collatz 10
10
5
16
8
4
2
1
moon>
Let’s implement two approaches of Fibonacci numbers.
Using the standard iterator, we simply don’t need to know the last result,
we can manage it inside a mutable state – it’s possible to implement it in only
one function using unpack
:
fib = (n) -> unpack {
-- Deal function
=>
return if @n == 0 -- stop
@a, @b, @n = @b, @a+@b, @n-1
@a -- step
-- Initial state
{a: 0, b: 1, :n}
}
And this works fine:
moon> print i for i in fib 10
1
1
2
3
5
8
13
21
34
55
Now Fibonacci numbers using coroutine:
fib = (n using coroutine) ->
import wrap, yield from coroutine
wrap ->
a, b = 0, 1
for _ = 1, n
a, b = b, a+b
yield a
The both approaches are performative, ’cause they use double accumulator to run a linear procedure.
Also in DEV.to.