удаление текущего слушателя из 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. Как я могу получить доступ к SaferEventListener (который я создам позже) из EventM, чтобы удалить его, когда произойдет событие?

В JavaScript вы используете выражение именованной функции в качестве обратного вызова для addEventListener, а затем применяете removeEventListener к этому имени из обратного вызова. Но здесь, похоже, ничего подобного быть не может. Или я что-то упускаю?


person Graham Leach-Krouse    schedule 02.03.2018    source источник


Ответы (1)


Используйте 1_

fixIO $ \rec -> newListener _eventm

Заполните _eventm своим EventM, и вы сможете получить доступ к прослушивателю событий, который в конечном итоге будет создан с помощью имени rec. rec будет результатом вызова 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 = fixIO), которые допускают такую ​​семантику завязывания узлов. GHC поддерживает "рекурсивную do" нотацию для любого MonadFix:

{-# LANGUAGE RecursiveDo #-}
someCode = mdo ...
               listener <- newListener _eventm -- can access listener in definition
               ...
-- or
someCode = do ...
              rec listener <- newListener _eventm
              ...
person HTNW    schedule 02.03.2018