从 EventM 中移除当前监听器
removing the current listener from within EventM
假设我想使用 ghcjs-dom 创建一个响应点击的事件侦听器,然后自行删除。
我有
addListener :: (IsEventTarget t, IsEvent e)
=> t -> EventName t e -> SaferEventListener t e -> Bool -> IO ()
removeListener :: (IsEventTarget t, IsEvent e)
=> t -> EventName t e -> SaferEventListener t e -> Bool -> IO ()
添加和删除,以及
newListener :: (IsEvent e) => EventM t e () -> IO (SaferEventListener t e)
从 EventM
构造监听器。我怎样才能从 EventM
中访问 SaferEventListener
(我稍后才会构建),以便在事件发生时将其删除?
在 JavaScript 中,您使用命名函数表达式作为对 addEventListener
的回调,然后从回调中将 removeEventListener
应用于该名称。但这里似乎不可能有任何类似的东西。还是我遗漏了什么?
使用fixIO
fixIO $ \rec -> newListener _eventm
用您的 EventM
填充 _eventm
,您将能够访问最终将通过名称 rec
创建的事件侦听器。 rec
将是 newListener
调用的结果,但在执行之前它可以是 "used"。我说 "used," 是因为试图用 seq
或任何更强大的东西强制它会导致无限循环,但你应该做你正在做的事情。
fixIO
是 fix
:
的概括
-- the essence of recursion
fix :: (a -> a) -> a
fix f = let x = f x in x
-- equivalent but less performant and less relevant
fix f = f (fix f)
-- if you have used JS's "named anonymous functions"
-- this will seem very familiar
(fix (\fact n ->
if n <= 1 then 1 else n * fact (n - 1)
)) 3 = 6
-- JS:
-- (function fact(n) {
-- if(n <= 1) { return 1; } else { return n * fact(n - 1); }
-- })(3) === 6
-- but this has more power
repeat = fix . (:)
repeat 1 = fix (1:) =
let x = 1:x in x = 1:fix (1:) = [1,1,1,1,1,1,1,1,1,1,1,1,1,1...]
fix id = let x = id x in x = let x = x in x = _|_ -- oops!
fixIO :: (a -> IO a) -> IO a
fixIO f = _ -- horrendous, unsafe code
fixIO (\xs -> return $ 1:xs) = return [1,1,1,1,1,1,1,1,1,1...]
fixIO return = fixIO (return . id) = return $ fix id = return _|_ -- oops!
fix
的想法是在函数实际创建之前使其可以使用其最终结果。
fixIO
的想法是在实际创建 之前使 IO
函数的最终结果可用,同时还执行一些 IO
操作 。此外,fixIO
仅执行这些操作 一次,这就是为什么 fix
的第一个定义(仅调用 f
一次)更相关的原因比第二个。
fixIO
又是 mfix :: MonadFix m => (a -> m a) -> m a
的特化,其中 MonadFix
是单子的 class(包括 IO
,mfix = fixIO
) 承认这样的 knot-tying 语义。 GHC 支持任何 MonadFix
:
的 "recursive do
" 符号
{-# LANGUAGE RecursiveDo #-}
someCode = mdo ...
listener <- newListener _eventm -- can access listener in definition
...
-- or
someCode = do ...
rec listener <- newListener _eventm
...
假设我想使用 ghcjs-dom 创建一个响应点击的事件侦听器,然后自行删除。
我有
addListener :: (IsEventTarget t, IsEvent e)
=> t -> EventName t e -> SaferEventListener t e -> Bool -> IO ()
removeListener :: (IsEventTarget t, IsEvent e)
=> t -> EventName t e -> SaferEventListener t e -> Bool -> IO ()
添加和删除,以及
newListener :: (IsEvent e) => EventM t e () -> IO (SaferEventListener t e)
从 EventM
构造监听器。我怎样才能从 EventM
中访问 SaferEventListener
(我稍后才会构建),以便在事件发生时将其删除?
在 JavaScript 中,您使用命名函数表达式作为对 addEventListener
的回调,然后从回调中将 removeEventListener
应用于该名称。但这里似乎不可能有任何类似的东西。还是我遗漏了什么?
使用fixIO
fixIO $ \rec -> newListener _eventm
用您的 EventM
填充 _eventm
,您将能够访问最终将通过名称 rec
创建的事件侦听器。 rec
将是 newListener
调用的结果,但在执行之前它可以是 "used"。我说 "used," 是因为试图用 seq
或任何更强大的东西强制它会导致无限循环,但你应该做你正在做的事情。
fixIO
是 fix
:
-- the essence of recursion
fix :: (a -> a) -> a
fix f = let x = f x in x
-- equivalent but less performant and less relevant
fix f = f (fix f)
-- if you have used JS's "named anonymous functions"
-- this will seem very familiar
(fix (\fact n ->
if n <= 1 then 1 else n * fact (n - 1)
)) 3 = 6
-- JS:
-- (function fact(n) {
-- if(n <= 1) { return 1; } else { return n * fact(n - 1); }
-- })(3) === 6
-- but this has more power
repeat = fix . (:)
repeat 1 = fix (1:) =
let x = 1:x in x = 1:fix (1:) = [1,1,1,1,1,1,1,1,1,1,1,1,1,1...]
fix id = let x = id x in x = let x = x in x = _|_ -- oops!
fixIO :: (a -> IO a) -> IO a
fixIO f = _ -- horrendous, unsafe code
fixIO (\xs -> return $ 1:xs) = return [1,1,1,1,1,1,1,1,1,1...]
fixIO return = fixIO (return . id) = return $ fix id = return _|_ -- oops!
fix
的想法是在函数实际创建之前使其可以使用其最终结果。
fixIO
的想法是在实际创建 之前使 IO
函数的最终结果可用,同时还执行一些 IO
操作 。此外,fixIO
仅执行这些操作 一次,这就是为什么 fix
的第一个定义(仅调用 f
一次)更相关的原因比第二个。
fixIO
又是 mfix :: MonadFix m => (a -> m a) -> m a
的特化,其中 MonadFix
是单子的 class(包括 IO
,mfix = fixIO
) 承认这样的 knot-tying 语义。 GHC 支持任何 MonadFix
:
do
" 符号
{-# LANGUAGE RecursiveDo #-}
someCode = mdo ...
listener <- newListener _eventm -- can access listener in definition
...
-- or
someCode = do ...
rec listener <- newListener _eventm
...