(Exceprt from an email to another researcher)
hi Paul, I follow your blog https://programmingsimplicity.substack.com/p/who-am-i-and-why-should-you-care because i share a similar insight about concurrency and asynchronicity and the relation to circuits and signals and have been working on that hypothesis for about 5 years. I work on https://github.com/hyperfiddle/electric which is a Clojure/Script implementation of our framing applied to the domain of server/client state distribution in UI programming.
Functional programming elides time and ordering. That's fine for ballistics computations. It is not fine for systems that need to respond to the world as it actually is — concurrent, event-driven, asynchronous by nature.
I actually don't agree with this. Consider this Clojure form, which you will agree can be cast as a DAG:
assuming inc, dec and + are effect-free functions, and forgetting imperative Clojure semantics to focus only on the DAG, a time ordering is directly implied: computing output c depends causally on first computing a and b, which can be computed concurrently, and both depend on input x which is computed once but consumed twice. Insight -> functional programming does not elide time/ordering, in our view it is the opposite.
At this point to be useful we must provide a language runtime that uses the DAG to auto-maximize concurrency at every point without breaking all the things programmers take for granted, such as control flow and lambda and equational consistency.
We must also find a way to define effects: let us only consider the set of effects which have an "undo" operation, such as malloc/free (memory), constructor/destructor (object), and mount/unmount (DOM) – i.e., resource effects. Resources allocate on first propagation through the DAG, and dispose when the DAG is disposed (e.g. by an if statement that switches, or by propagating a dispose signal through the process).
We can drive the system DAG to transition between two consistent states by firing mount and unmount lifecycle methods, to mount new nodes to the DAG and unmount old ones. The key to making it work is the reactive propagation engine under the hood needs to be essentially perfect ("glitch free") which means it fires exactly the correct lifecycle methods once and only once during reactive propagation, which is pretty hard to do correctly. I.e. you don't want to allocate a node twice or dispose it twice, it needs to be perfect.
We've demonstrated that this is a suitable foundation for rich user interfaces on the web platform, such as https://github.com/hyperfiddle/datomic-browser, or here's another live demo you can click around in: (ManagementFactory/getPlatformManagementInterfaces) -- the point being web apps are a concrete real-world application which is "concurrent, event-driven and asynchronous by nature" (i.e., "reactive")
The functional effect concurrency framework we use to implement this is https://github.com/leonoel/missionary (authored by my co-founder)
The big question then is "What is functional programming?" And in our view it is "the study of time, concurrency and causality"