为什么回调堆栈大小超过我使用的绑定语法?
Why does the callback stack size exceed depending on the bind syntax I use?
我有两个代码变体,应该只是语法不同,但也许我错了。第一个导致“回调堆栈大小超过”/“太多递归”。
main :: Effect Unit
main = do
w <- window
loop w
loop :: Window -> Effect Unit
loop w = redraw <* requestAnimationFrame (loop w) w
redraw :: Effect Unit
redraw = log "Redrawing endlessly!"
通过像这样改变loop
函数,我可以避免这个问题:
loop :: Window -> Effect Unit
loop = do
redraw
requestAnimationFrame (loop w) w $> unit
为什么?
loop
函数的第一个版本总是立即无条件地调用自身:
loop w = redraw <* requestAnimationFrame (loop w) w
^^^^^^^^
right here
每次有人调用 loop
时,它会立即调用 loop w
。它必须立即调用 loop w
,因为它需要将其 return 值作为第一个参数传递给 requestAnimationFrame
,它需要将第二个参数传递给运算符 <*
,这它需要调用以提供自己的 return 值。无限循环,就在那里。
然而,do
语法被脱糖为 lambda-expression 和对运算符 >>=
的调用,如下所示:
loop w =
redraw >>= (\x -> requestAnimationFrame (loop w) w $> unit)
这里,递归调用 loop w
不会立即发生,而是被包装在 lambda-expression 中,然后作为第二个参数传递给运算符 >>=
。只有在计算 lambda 表达式的主体时才会发生递归调用。
我有两个代码变体,应该只是语法不同,但也许我错了。第一个导致“回调堆栈大小超过”/“太多递归”。
main :: Effect Unit
main = do
w <- window
loop w
loop :: Window -> Effect Unit
loop w = redraw <* requestAnimationFrame (loop w) w
redraw :: Effect Unit
redraw = log "Redrawing endlessly!"
通过像这样改变loop
函数,我可以避免这个问题:
loop :: Window -> Effect Unit
loop = do
redraw
requestAnimationFrame (loop w) w $> unit
为什么?
loop
函数的第一个版本总是立即无条件地调用自身:
loop w = redraw <* requestAnimationFrame (loop w) w
^^^^^^^^
right here
每次有人调用 loop
时,它会立即调用 loop w
。它必须立即调用 loop w
,因为它需要将其 return 值作为第一个参数传递给 requestAnimationFrame
,它需要将第二个参数传递给运算符 <*
,这它需要调用以提供自己的 return 值。无限循环,就在那里。
然而,do
语法被脱糖为 lambda-expression 和对运算符 >>=
的调用,如下所示:
loop w =
redraw >>= (\x -> requestAnimationFrame (loop w) w $> unit)
这里,递归调用 loop w
不会立即发生,而是被包装在 lambda-expression 中,然后作为第二个参数传递给运算符 >>=
。只有在计算 lambda 表达式的主体时才会发生递归调用。