Open rgrempel opened 8 years ago
It occurs to me that the other way to deal with the common base signals would be to have a StateT
with a Maybe
slot for each base signal. Then, when one needs the base signal, you either just read it from the StateT
or, if it's Nothing
, you actually create it and store it there.
The potential advantage of this is that you'd only need one setup
method with a callback ... you wouldn't need a separate setupMouse
, setupKeyboard
, setupWindow
etc.
The disadvantage, I suppose, is that this integrated setup
method would need to import a wide cross-section of stuff. However, it would probably only need to actually use the types. And, in fact, to avoid circular imports, I'd probably need to specify the types in separate modules. So, it probably wouldn't draw unnecessary code into the build. (And, we do have dead-code elimination in any event, after all).
In any event, it's an option worth exploring.
Yet another way of structuring this (possibly) would be via Lazy
, rather than Maybe
... that is, I think the Lazy
structure is another way of saying "do this only once, if ever needed, and then keep giving the same answer".
When I revisit this code again, my hope would be to restructure so that it expresses the Signals API in terms of Elm 0.18's programs or effects managers ... there are some curious analogies between them that may or may not amount to something.
In order to match the simplicity of some Elm APIs, I've been using
ReaderT
andStateT
in places likeElm.Signal
,Elm.Mouse
andElm.Keyboard
.The way in which this simplifies the API is that some things which would otherwise need to be parameters to multiple functions can be provided once (or, in some cases, generated once), and then consulted by multiple functions without an explicit parameter. (So, the ordinary reason for
ReaderT
andStateT
, I think).The other way in which this helps is by creating "singletons" for some effectful things that the Elm API re-uses. For instance, the Elm API often has a "base" signal, like
Mouse.position
, and then some signals mapped from it, likeMouse.x
andMouse.y
. The way that the Elm API handles this is by generating all defined signals (if the module was imported at all) at run-time, and then pruning those which were not used (in the sense of not connected to something in the signal graph that generates effects). So, bothMouse.x
andMouse.y
can depend on oneMouse.position
, because theMouse.position
is actually generated.It would (I think) be difficult to follow that exact strategy in Purescript (though perhaps not impossible) -- and, in any event, it would be interesting to experiment with an approach that only creates the signals that are desired (so that no pruning stage is needed). One way to do this would be to change the signature of something like
Mouse.x
to require aSignal MousePosition
as a parameter. So, you'd manually create aMouse.position
and then supply that toMouse.x
. However, I'd like to change the Elm APIs as little as possible. So, the alternative is to provide asetupMouse
function that takes a callback which runs within aReaderT
that has access to aSignal MousePosition
. In this way, the original Elm API can be supported, at the cost of adding a function call to setup the callback. (This works particularly well inElm.Keyboard
, where the common base structures are repeatedly re-used).I'm looking at
Elm.Window
now, and realizing that one of the things it needs is the "container" node (possibly the<body>
, but not necessarily), which is also needed byElm.Mouse
. So, one really ought to integrate those things ... for instance, by having anElm.Runtime
module that has aReaderT
orStateT
that tracks the container node. The idea being that you only need to specify the container node once.In fact, this integrated superstructure might also be a good place to locate the signal graph, since if you need
Elm.Mouse
orElm.Window
, then you obviously also needElm.Signal
, so there would be no waste. (There would be little waste in any event in just setting up an empty signal graph). So, we might be able to entirely integrate thesetup
method fromElm.Signal
into anElm.Runtime
. We'd probably still need a separatesetupMouse
andsetupKeyboard
function (for the common base signals -- we wouldn't want to generate those more than once, or when not needed), but at least we could integrate some things.So, I should look at establishing an
Elm.Runtime
module at some point.