Existe-t-il un moyen d'écrire une fonction f :: (a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t)
, fondamentalement liftMn
pour tout n
?Ecriture d'une fonction (a -> b -> ... -> t) -> (Monad m => ma -> mb -> ... -> mt)
(EDIT: exemple de sens fixe.)
Je vous écris une bibliothèque de FRP, et je pensais que ce serait propre si je pouvais avoir le code vaguement:
main = do
input1 <- signalFromTextBoxTheUserMayTypeANumberInto
input2 <- signalFromAnotherTextBox
divided <- signal div input1 input2
signal (\x -> showTextAlert ("input1 `div` input2 is " ++ show x)) divided
Je suis tripoter avec des familles de types pour le faire fonctionner, mais je commence à penser que ce n'est pas réalisable. Je suis actuellement en train de faire quelque chose comme ceci:
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 =
\[email protected](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
Cela ne fonctionne évidemment pas, comme le unsafePerformIO s'évalué une fois et conserve ensuite cette valeur, et si elle ne fonctionnait serais toujours laid, aki et généralement mal . Y a-t-il un moyen de le faire, ou devrais-je simplement abandonner l'idée?
Demandez-vous: Est-ce que je peux donner un type raisonnable à ce combinateur? Sinon, quel type de magie noire est nécessaire pour lui donner un type raisonnable? Cela pourrait être utile: [Comment créer une fonction haskell polyvariadique?] (Http://stackoverflow.com/q/3467279/417501) – fuz