You're right, this is an interesting way to implement dependency injection.
A big problem this approach solves is that it avoids code that relies on injected code from needing to predict in advance all the things that injected code might need to do. This problem is much less pronounced in a dynamically typed language (since you haven't had to predict the type signature of the injected code).
In javascript the most significant time this is a problem is when the injected code might need to be asynchronous. In standard javascript, if that's the case, the surrounding code needs to know about it.
In Haskell, you have the same problem doing something as simple as debug logging.
My concern is just that adding effects reduces how much you know about what a particular function does just by looking at it, and this is true in both typed and untyped languages.
A big problem this approach solves is that it avoids code that relies on injected code from needing to predict in advance all the things that injected code might need to do. This problem is much less pronounced in a dynamically typed language (since you haven't had to predict the type signature of the injected code).
In javascript the most significant time this is a problem is when the injected code might need to be asynchronous. In standard javascript, if that's the case, the surrounding code needs to know about it.
In Haskell, you have the same problem doing something as simple as debug logging.
My concern is just that adding effects reduces how much you know about what a particular function does just by looking at it, and this is true in both typed and untyped languages.