0

假设我想使用 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. 如何SaferEventListener从 中访问(我稍后将构建)EventM,以便在事件发生时将其删除?

在 JavaScript 中,您使用命名函数表达式作为对 的回调addEventListener,然后removeEventListener从回调中应用到该名称。但这里似乎没有任何类似的东西是可能的。还是我错过了什么?

4

1 回答 1

3

利用fixIO

fixIO $ \rec -> newListener _eventm

填写_eventm您的EventM,您将能够访问最终将通过名称创建的事件侦听器recrec将是newListener调用的结果,但它可以在执行之前“使用”。我说“使用过”,因为试图用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的单子类(包括IO,与)。mfix = fixIOGHC 支持任何“递归do”表示法MonadFix

{-# LANGUAGE RecursiveDo #-}
someCode = mdo ...
               listener <- newListener _eventm -- can access listener in definition
               ...
-- or
someCode = do ...
              rec listener <- newListener _eventm
              ...
于 2018-03-02T21:24:13.843 回答