Есть ли способ написать функцию f :: (a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t)
, в основном liftMn
для любого n
?
(РЕДАКТИРОВАТЬ: исправлен бессмысленный пример.)
Я пишу библиотеку FRP, и подумал, что было бы здорово, если бы у меня был смутный код вроде:
main = do
input1 <- signalFromTextBoxTheUserMayTypeANumberInto
input2 <- signalFromAnotherTextBox
divided <- signal div input1 input2
signal (\x -> showTextAlert ("input1 `div` input2 is " ++ show x)) divided
Я возился с семействами типов, чтобы заставить его работать, но я начинаю думать, что это на самом деле невозможно. В настоящее время я делаю что-то вроде этого:
type Action a = IORef a -> IO ()
type Listener = IO ()
newtype Signal a = Signal (IORef (SigData a))
data SigData a = SigData {
trigger :: Action a,
output :: IORef a,
listeners :: [Listener]
}
class Sig a where
type S a
mkSig :: [AnySignal] -> a -> S a
instance Sig b => Sig (a -> b) where
type S (a -> b) = Signal a -> S b
mkSig dependencies f =
\s@(Signal sig) ->
let x = unsafePerformIO $ readIORef sig >>= readIORef . output
in mkSig (AnySignal s : dependencies) (f x)
instance Sig Int where
type S Int = IO (Signal Int)
out <- newIORef x
self <- Signal <$> (newIORef $ SigData {
trigger = \ref -> writeIORef ref $! x,
output = out,
listeners = []
})
mapM_ (self `listensTo`) deps
return self
Это, очевидно, не работает, поскольку unsafePerformIO оценивается один раз, а затем сохраняет это значение, и если оно сработало, оно все равно будет уродливым, хакерским и, как правило, злым. Есть ли способ сделать это, или я просто должен отпустить идею?