Most of the time, we don't need to have a dynamic call sub graph, since
the actual function call could be represented statically as it
originally was before lambda functions were implemented. Simplifying the
graph shape has important performance benefits in terms of both keep the
graph smaller (memory, etc) and in avoiding the need to run transactions
at runtime (speed) to reshape the graph.
Co-authored-by: Samuel Gélineau <gelisam@gmail.com>
Instead of constantly making these updates, let's just remove the year
since things are stored in git anyways, and this is not an actual modern
legal risk anymore.
This is needed for bigger code bases. Remember: this is consulted at the
deploy stage, and the deploy contains the entire tree (including
modules) of everything it needs to run. This is why you don't need to
add a --module-path arg when running mgmt in systemd with the "empty"
frontend.
Here's a good first way to implement handoff. What's particularly
elegant about handoff here, is that this is the first form of it I know,
where handoff happens between a provisioning tool and a configuration
management tool and those are the same tool! As a result, this can allow
for some really elegant integration, and the end-user never has to deal
with the combinatorial explosion of the N * M scenario of gluing each
provisioning tool to each different configuration management tool.
We'll have other forms of handoff in the future, but this simple
approach is useful already.
This adds a modern type unification algorithm, which drastically
improves performance, particularly for bigger programs.
This required a change to the AST to add TypeCheck methods (for Stmt)
and Infer/Check methods (for Expr). This also changed how the functions
express their invariants, and as a result this was changed as well.
This greatly improves the way we express these invariants, and as a
result it makes adding new polymorphic functions significantly easier.
This also makes error output for the user a lot better in pretty much
all scenarios.
The one downside of this patch is that a good chunk of it is merged in
this giant single commit since it was hard to do it step-wise. That's
not the end of the world.
This couldn't be done without the guidance of Sam who helped me in
explaining, debugging, and writing all the sneaky algorithmic parts and
much more. Thanks again Sam!
Co-authored-by: Samuel Gélineau <gelisam@gmail.com>
Plumb through the standard context.Context so that a function can be
cancelled if someone requests this. It makes it less awkward to write
simple functions that might depend on io or network access.
This adds a unification optimizations API, and uses it to optimize the
embedded provisioner. With these turned on, type unification drops from
around 1m45s to 2.5s which is a 40x speedup.
This commit adds the ability to build a standalone provisioning tool.
This is the first useful public mcl code base as well. It is not
perfect, but does serve as a rough starting point to show what is
possible. In the future as the language and the engine evolve, this will
likely get more elegant, and also grow new features.
To build this, run `make clean && GOTAGS='embedded_provisioner' make`.
To run this, run `mgmt provisioner`.