Background
I have some code that uses list comprehensions in elixir and performs some long operations. I need this code to be lazily evaluated instead of running immediately (eager evaluation).
Code
Imagine I have a list comprehension like the following:
for a <- long_operation(),
b <- longer_operation() do
a + b
end
Now, here a
and b
will be eagerly evaluated, so as to return a + b
. However, both long_operation()
and longer_operation()
take a very long time to run (as the name implies) and I will only absolutely run them if I have to.
I want to come up with a solution that allows for my code to be lazily evaluated. Say, for example, to have a data structure or some other construct where I can then call run()
to actually do the hard work.
Research
My first idea was to just put everything inside of anonymous functions:
for a <- fn -> long_operation() end,
b <- fn -> longer_operation() end do
a + b
end
This worked as well as you would expect, i.e., it didn’t. The main reason being: “You cannot sum two functions”.
And it makes sense.
My next option is then to have a data-structure hold the values of these computations, and have the list comprehension return said data-structure.
I would then call run()
or something similar, and then the operation would be executed.
You can probably think of this as the IO
construct in languages like Scala or Haskell (pardon for the poor comparison).
Other people have suggested the use of GenServer
s to achieve this, but this avenue does not sit well with me for two main reasons:
- I am adding a runtime dependency to a code that should not even know
GenServer
s exist in the first place. - Also I fail to see how this would help in any way.
Problem
The issue here is that I believe this will force me to implement a mini AST with the instructions of what needs to be executed when I call run()
. Not only do I lack the knowledge to do this, It also sounds overkill at first glance.
Surely, Elixir has a way to have expressions being lazily evaluated that I am not aware of.
So this brings me to the question:
- What mechanisms does Elixir use to have lazy evaluation?
- Are there any data-structures/libraries out there that do this? (lazy evaluation)
Please let me know!