Depends on D20446. Currently, chart functions are both configured through arguments and evaluated through arguments. This sort of conflates things and makes some logic more difficult than it should be.
- Function arguments are used to configure function behavior. For example, scale(2) configures a function which does f(x) => 2 * x.
- Evaluation is now separate, after configuration.
We can get rid of "sourceFunction" (which was basically marking one argument as "this is the thing that gets piped in" in a weird magical way) and "canEvaluate()" and "impulse".
Sequences of functions are achieved with compose(u, v, w), which configures a function f(x) => w(v(u(x))) (note order is left-to right, like piping x | u | v | w to produce y).
The new flow is:
- Every chartable function is compose(...) at top level, and composes one or more functions. compose(x) is longhand for id(x). This just gives us a root/anchor node.
- Figure out a domain, through various means.
- Ask the function for a list of good input X values in that domain. This lets function chains which include a "fact" with distinct datapoints tell us that we should evaluate those datapoints.
- Pipe those X values through the function.
- We get Y values out.
- Draw those points.
- Adds accumluate().
- Adds sum(), which is now easy to implement.
- Adds compose().
- All functions can now always evaluate everywhere, they just return null if they are not defined at a given X.
- Adds repeatable arguments for compose(f, g, ...) and sum(f, g, ...).