PureScript 函数在运行时给出错误的类型
PureScript functions giving wrong type at runtime
这是我用 PureScript 编写的函数。它编译时没有错误或警告。该函数做了一些设置来处理鼠标移动:
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
和 velocityRef
是引用可变变量的 STRef
变量。它们由调用函数传入。
下面是同一代码片段的编译 JavaScript 版本:
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)();
};
};
};
这就是我面临的问题:这段代码的重点是使用从鼠标移动中获得并存储在 newAngle
中的新计算角度调用 rotateCube
函数。
但是,当我 运行 在浏览器中使用这段代码时,它并没有按照我的意愿执行。然后我尝试调试 JavaScript 代码,我发现 newAngle
变量最终的值为
{ x: NaN, y: NaN }
跟踪代码后我发现原因是因为变量v5.x
(在PureScript中是angle.x
)有一个Number
类型的值,但是变量v2
和v4.x
(x
和lastPos.x
)具有以下类型
v2: Object[1]
0: 127
length: 1
而不是 Number
。同样的事情发生在 y
和 lastPos.y
的情况下。我猜测将此与 angle.x
的 Number
类型相加会导致 NaN
。但为什么会这样呢?为什么 x
和 lastPos.x
在 javascript 的 运行 时间不是 Number
而是看起来像这些数组?
我不确定这是否是一个线索,但是 Control.Monad.Eff.JQuery
中的 on
函数将一个函数作为参数(在本例中为 moveHandler
)将在事件发生时执行,该函数的类型应为
(JQueryEvent -> JQuery -> Eff (dom :: DOM | eff) a))
但是在moveHandler
里面我有两个副作用,一个是DOM
,另一个是ST
因为使用了readSTRef
.
我实际上尝试在 moveHandler
的定义之前显式声明其类型
moveHandler :: forall e h. JQueryEvent -> JQuery -> Eff (dom :: DOM, st :: ST h | eff) Unit))
但这总是会给我一个 Could not match type
错误,这就是为什么我最终没有提到 moveHandler
的显式类型的原因。这可能是代码不起作用的原因吗?在事件处理程序回调函数中不可能也发生 ST
效果吗?
正如 Phill Freeman 和 Yury Tarabanko 在评论中所建议的那样,事实证明 purescript-jquery
中的 getPageX/Y
是 return 错误的类型。现在已更正,更新包后,程序按原样执行并且 newAngle
具有正确的值。
尽管 getPageX/Y
的 return 类型不正确解释了为什么 x
和 y
不正确,但我仍然对为什么 lastPos.x
和 lastPos.y
也是不正确的类型,即使它们是由 readSTRef
分配的。直到现在我才意识到我愚蠢的大脑没有考虑清楚。 lastPos
存储最后一个鼠标位置,该位置是 也 从 getPageX/Y
获得的。所以这两种奇怪的类型都是由同一个错误引起的。
这是我用 PureScript 编写的函数。它编译时没有错误或警告。该函数做了一些设置来处理鼠标移动:
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
和 velocityRef
是引用可变变量的 STRef
变量。它们由调用函数传入。
下面是同一代码片段的编译 JavaScript 版本:
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)();
};
};
};
这就是我面临的问题:这段代码的重点是使用从鼠标移动中获得并存储在 newAngle
中的新计算角度调用 rotateCube
函数。
但是,当我 运行 在浏览器中使用这段代码时,它并没有按照我的意愿执行。然后我尝试调试 JavaScript 代码,我发现 newAngle
变量最终的值为
{ x: NaN, y: NaN }
跟踪代码后我发现原因是因为变量v5.x
(在PureScript中是angle.x
)有一个Number
类型的值,但是变量v2
和v4.x
(x
和lastPos.x
)具有以下类型
v2: Object[1]
0: 127
length: 1
而不是 Number
。同样的事情发生在 y
和 lastPos.y
的情况下。我猜测将此与 angle.x
的 Number
类型相加会导致 NaN
。但为什么会这样呢?为什么 x
和 lastPos.x
在 javascript 的 运行 时间不是 Number
而是看起来像这些数组?
我不确定这是否是一个线索,但是 Control.Monad.Eff.JQuery
中的 on
函数将一个函数作为参数(在本例中为 moveHandler
)将在事件发生时执行,该函数的类型应为
(JQueryEvent -> JQuery -> Eff (dom :: DOM | eff) a))
但是在moveHandler
里面我有两个副作用,一个是DOM
,另一个是ST
因为使用了readSTRef
.
我实际上尝试在 moveHandler
的定义之前显式声明其类型
moveHandler :: forall e h. JQueryEvent -> JQuery -> Eff (dom :: DOM, st :: ST h | eff) Unit))
但这总是会给我一个 Could not match type
错误,这就是为什么我最终没有提到 moveHandler
的显式类型的原因。这可能是代码不起作用的原因吗?在事件处理程序回调函数中不可能也发生 ST
效果吗?
正如 Phill Freeman 和 Yury Tarabanko 在评论中所建议的那样,事实证明 purescript-jquery
中的 getPageX/Y
是 return 错误的类型。现在已更正,更新包后,程序按原样执行并且 newAngle
具有正确的值。
尽管 getPageX/Y
的 return 类型不正确解释了为什么 x
和 y
不正确,但我仍然对为什么 lastPos.x
和 lastPos.y
也是不正确的类型,即使它们是由 readSTRef
分配的。直到现在我才意识到我愚蠢的大脑没有考虑清楚。 lastPos
存储最后一个鼠标位置,该位置是 也 从 getPageX/Y
获得的。所以这两种奇怪的类型都是由同一个错误引起的。