Use fixIO
fixIO $ \rec -> newListener _eventm
Fill _eventm
with your EventM
, and you will be able to access the event listener that will eventually be created through the name rec
. rec
will be the result of the newListener
call, but it can be "used" before that is executed. I say "used," because trying to force it with seq
or anything stronger will cause an infinite loop, but you should be fine doing what you're doing.
fixIO
is a generalization of 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!
The idea of fix
is making a function's eventual result available to it before it is actually created.
The idea of fixIO
is making an IO
function's eventual result available to it before it is actually created while also carrying out some IO
actions. Also, fixIO
only carries out these actions once, which is why the first definition of fix
(that only calls f
once) is more relevant than the second.
fixIO
, in turn, is a specialization of mfix :: MonadFix m => (a -> m a) -> m a
, where MonadFix
is the class of monads (including IO
, with mfix = fixIO
) that admit such knot-tying semantics. GHC supports "recursive do
" notation for any MonadFix
:
{-# LANGUAGE RecursiveDo #-}
someCode = mdo ...
listener <- newListener _eventm -- can access listener in definition
...
-- or
someCode = do ...
rec listener <- newListener _eventm
...