Skip to content

Instantly share code, notes, and snippets.

@prophile
Created July 11, 2013 05:21
Show Gist options
  • Save prophile/5972716 to your computer and use it in GitHub Desktop.
Save prophile/5972716 to your computer and use it in GitHub Desktop.
A third rough sketch of an FRP system in Haskell.
{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, RankNTypes, MonadComprehensions, TupleSections #-}
import Control.Applicative
import Data.Monoid
import Control.Monad
import Control.Monad.Cont
import Control.Concurrent.MVar
import Data.IORef
newtype SignalIn m a = SignalIn (Cont (m ()) a)
deriving (Functor, Applicative,
Monad)
instance (Monad m) => MonadPlus (SignalIn m) where
mzero = SignalIn $ cont $ const $ return ()
x `mplus` y = SignalIn $ cont $ liftM2 (>>) (x $>) (y $>)
instance (MonadIO m) => MonadIO (SignalIn m) where
liftIO z = SignalIn $ cont $ \k -> do
(liftIO z) >>= k
return mempty
type Signal = SignalIn IO
newBus :: (MonadIO m) => m (SignalIn m a, SignalIn m a -> m ())
newBus = do receivers <- (liftIO $ newMVar [])
let addReceiver x = liftIO $ modifyMVar_ receivers (return . (x:))
let broadcast x = do receivers <- liftIO $ readMVar receivers
forM_ receivers ($ x)
return (SignalIn $ cont addReceiver, ($> broadcast))
($>) :: (Monad m) => SignalIn m a -> (a -> m ()) -> m ()
(SignalIn c) $> f = c `runCont` f
newtype PropertyIn m a = Property (forall b. SignalIn m b -> SignalIn m (a, b))
instance (Monad m) => Functor (PropertyIn m) where
fmap f (Property g) = Property $ \s -> [(f x, y) | (x, y) <- g s]
propJoin :: (Monad m) => PropertyIn m (PropertyIn m a) -> PropertyIn m a
propJoin (Property g) = Property $ \s ->
g s >>= (\(Property sampled, stream) -> sampled (return stream))
instance (Monad m) => Applicative (PropertyIn m) where
pure = return
(<*>) = ap
instance (Monad m) => Monad (PropertyIn m) where
return x = Property $ \e -> fmap (x, ) e
p >>= f = propJoin $ fmap f p
sample :: (Monad m) => SignalIn m a -> PropertyIn m b -> SignalIn m (b, a)
sample s (Property f) = f s
type Property = PropertyIn IO
toProperty :: (MonadIO m) => SignalIn m a -> m (PropertyIn m a)
toProperty s = do currentValue <- liftIO $ newIORef Nothing
s $> \value -> do liftIO $ writeIORef currentValue (Just value)
return ()
let sampleStream s = do sampleValue <- s
propValue <- liftIO $ readIORef currentValue
case propValue of
Just x -> return (x, sampleValue)
Nothing -> mzero
return $ Property sampleStream
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment