As luck would have it, this morphed from a “how do I?” question into an “is this right?” question. This is my first go at writing an effectful binding, so I want to make sure that even if it works, I’m not introducing some subtle misbehavior.
Here is a gist with the main module, foreign module, and compiled output: https://gist.github.com/smilack/b2026158f0b35e5dbc4d271009d87614.
Motivation: The callback given to Window.requestAnimationFrame can take an argument - the timestamp marking the beginning of the animation frame - but the current FFI to requestAnimationFrame (JS implementation) doesn’t support this.
I started by changing the Effect Unit
types to Number -> Effect Unit
and using the same JavaScript implementation.
foreign import _requestAnimationFrame :: Effect Unit -> Window -> Effect Int
requestAnimationFrame :: Effect Unit -> Window -> Effect RequestAnimationFrameId
foreign import _requestAnimationFrameWithTime :: (Number -> Effect Unit) -> Window -> Effect Int
requestAnimationFrameWithTime :: (Number -> Effect Unit) -> Window -> Effect RequestAnimationFrameId
However, the callback for requestAnimationFrameWithTime
never ran. I looked at the compiled code (I didn’t realize how great readable output is until now!), and found that the callback with an argument is wrapped in an extra function:
var callbackWithTime = function (time) {
return Effect_Console.log("callback with time: " + Data_Show.show(Data_Show.showNumber)(time));
};
var callback = Effect_Console.log("callback without time");
So requestAnimationFrame
was calling callbackWithTime
but discarding the return value - which is what I actually wanted it to call.
I wrestled with the type checker for a while but couldn’t reconcile the fact that the issue was occurring within requestAnimationFrame
, so I realized the problem had to be on the JS side.
To solve it I added an anonymous function which is passed as the callback to requestAnimationFrame
. It receives the timestamp value, passes it into the provided callback, and then calls the returned function:
exports._requestAnimationFrameWithTime = function(fn) {
return function(window) {
return function() {
return window.requestAnimationFrame(function(time) {
fn(time)();
});
};
};
};
So I guess my only question is - is there anything wrong with this?
A note on DOMHighResTimeStamp
: MDN says the callback is passed a DOMHighResTimeStamp
, but I couldn’t find a definition for it anywhere in PureScript. I looked at the High Resolution Time spec and found that it’s an alias for double, just like JavaScript’s Number
. I also double-checked with the Web Interface Definition Language spec, which says typedefs
are for use in writing specs only, and are not part of the language described. So I think Number
is the correct type for the callback’s parameter.