1
votes

Here's a function I wrote in PureScript. It compiles with no errors or warnings. The function does some setting up to handle mouse movement:

startMouseHandlers :: forall h e. STRef h {x::Number, y::Number}
  -> STRef h {x::Number, y::Number}
  -> Eff (dom :: DOM, st :: ST h | e) Unit
startMouseHandlers angleRef velocityRef = do
  lastMousePos <- newSTRef {x: 0.0, y: 0.0}
  body <- JQuery.body
  let
    moveHandler event jq = do
    x <- getPageX event
    y <- getPageY event
    lastPos <- readSTRef lastMousePos
    angle <- readSTRef angleRef
    let newAngle = {
          x: angle.x + x - lastPos.x,
          y: angle.y + y - lastPos.y
        }
    rotateCube angleRef newAngle
    void $ writeSTRef lastMousePos {x: x, y: y}
  on "mousemove" movehandler body

angleRef and velocityRef are STRef variables that reference mutable variables. They are being passed in by a calling function.

And here's the compiled JavaScript version of the same code snippet:

var startMouseHandlers = function (angleRef) {
      return function (velocityRef) {
      return function __do() {
          var v = Control_Monad_ST.newSTRef({
              x: 0.0, 
              y: 0.0
          })();
          var v1 = Control_Monad_Eff_JQuery.body();
          var moveHandler = function (event) {
              return function (jq) {
                  return function __do() {
                      var v2 = Control_Monad_Eff_JQuery.getPageX(event)();
                      var v3 = Control_Monad_Eff_JQuery.getPageY(event)();
                      var v4 = Control_Monad_ST.readSTRef(v)();
                      var v5 = Control_Monad_ST.readSTRef(angleRef)();
                      var newAngle = {
                          x: (v5.x + v2) - v4.x, 
                          y: (v5.y + v3) - v4.y
                      };
                      rotateCube(angleRef)(newAngle)();
                      return Data_Functor["void"](Control_Monad_Eff.functorEff)(Control_Monad_ST.writeSTRef(v)({
                          x: v2, 
                          y: v3
                      }))();
                  };
              };
          };
          return Control_Monad_Eff_JQuery.on("mousemove")(moveHandler)(v1)();
      };
      };
  };

This is the problem I'm facing: The point of this snippet is to call the rotateCube function with the newly calculated angle obtained from the mouse movement and stored in newAngle.

However, when I run this code in the browser, it doesn't do what I want it to do. I then tried debugging the JavaScript code and I discovered that the newAngle variable ends up having the value of

{ x: NaN, y: NaN }

After tracing the code I found out the reason was because the variable v5.x (which is angle.x in PureScript) has a value that is of Number type, but the variables v2 and v4.x (x and lastPos.x) have the following type

v2: Object[1]
  0: 127
  length: 1

instead of being a Number. The same thing happens in the case of y and lastPos.y. I'm guessing the addition of this with the Number type of angle.x results in NaN. But why is that happening? Why aren't x and lastPos.x turning out to be Numbers at runtime in javascript and instead look like these arrays?

I'm not sure if this is a clue or not, but the on function in Control.Monad.Eff.JQuery takes a function as an argument (in this case, moveHandler) that will be executed when the event occurs and that function should be of type

(JQueryEvent -> JQuery -> Eff (dom :: DOM | eff) a))

But inside moveHandler I have two side effects, one is DOM and the other is ST because of using readSTRef.

I actually tried explicitly declaring the type for moveHandler before it's definition like this

moveHandler :: forall e h. JQueryEvent -> JQuery -> Eff (dom :: DOM, st :: ST h | eff) Unit))

But this would always give me a Could not match type error, which is why I ended up just not mentioning an explicit type for moveHandler. Could this be a reason why the code isn't working? Is it not possible to have an ST effect also happening in the event handler callback function?

1
It's possible that the type of getPageX is wrong in purescript-jquery.Phil Freeman
But it's not just x and y that have the problem. Even lastPos.x and lastPos.y end being an array instead of Number type, but they get their values from the readSTRef function. Also worth mentioning, I have another fuction in my program that also uses readSTRef but over there the value is assigned normally so I'm really confused as to why this is happening only inside moveHandlerGeorge V.M.
getPageX returns jQuery instance instead of a NumberYury Tarabanko
Is there something I can do to fix that?George V.M.
@GeorgeV.M. A pull request fixing the issue? :)Yury Tarabanko

1 Answers

0
votes

As suggested by Phill Freeman and Yury Tarabanko in the comments, it turned out that getPageX/Y in purescript-jquery was returning the wrong type. It's been corrected now and after updating the package, the program executes as is and newAngle has the correct value.

Although an incorrect return type for getPageX/Y explains why x and y were incorrect, I was still confused about why lastPos.x and lastPos.y were also incorrect types even though they were assigned by readSTRef. It's only now that I realized my silly brain didn't think it through. lastPos stores the last mouse position and that position is also obtained from getPageX/Y. So both the weird types were caused by the same error.