turion / rhine

Haskell Functional Reactive Programming framework with type-level clocks
http://hackage.haskell.org/package/rhine
118 stars 21 forks source link

Millisecond clock transformers #193

Closed SheetKey closed 1 year ago

SheetKey commented 1 year ago

I am working on some things with signal network control flow via ExceptT and have run into some troubles working with Millisecond clocks.

type Second = Millisecond 1000
type Second2 = Millisecond 2000

example1 :: Rhine (ExceptT e IO) (ParClock (ExceptT e IO) Second Second2) () ()
example1 = constMCl (liftIO $ putStrLn "Title") @@ waitClock
          ||@ hoistSchedule liftIO scheduleMillisecond @||
          constMCl (liftIO $ putStrLn "Press enter to start") @@ waitClock

Here I get errors that there is no instance for (Clock (ExceptT e IO) Second). I tried this as well

example2 :: Rhine (ExceptT e IO) (ParClock (ExceptT e IO) Second Second2) () ()
example2 = constMCl (liftIO $ putStrLn "Title") @@ waitClock
           ||@ concurrentlyExcept @||
           constMCl (liftIO $ putStrLn "Press enter to start") @@ waitClock

Which has the same error. I tried using IOClock, but then I don't know how to also lift that clock and schedule data into MonadIO.

example3 :: Rhine (ExceptT e IO) (IOClock (ExceptT e IO) (ParClock IO Second Second2)) () ()
example3 = constMCl (liftIO $ putStrLn "Title") @@ waitClock
           ||@ scheduleMillisecond @||
           constMCl (liftIO $ putStrLn "Press enter to start") @@ waitClock

Is there a way to do this that I'm missing?

If not generalizing Millisecond n to use MonadIO would be handy. I tried changing it to

newtype Millisecond (n :: Nat) = forall m . MonadIO m => Millisecond (RescaledClockS m (FixedStep n) UTCTime Bool)

however the clock instance will not work since it cannot verify that for Clock m1 (Millisecond n) and RescaledCLockS m2 (FixedStep n) UTCTime Bool), m1=m2. Changing the signature of Millisecond n to Millisecond m n works but is a rather major change.

This seems possibly related to #61 and #62.

SheetKey commented 1 year ago

Dumb question should have given it more thought. Just need to instantiate HoistClock

turion commented 1 year ago

It's a good question, thanks for asking! I've ended up this train of thoughts myself before a few times, and with the current code base, HoistClock (or rather LiftClock in your case) is the best choice.

If not generalizing Millisecond n to use MonadIO would be handy.

Yes it would. It doesn't work as a RescaledClockS as you've seen, so it would have to be implemented directly, as a singleton. Which is probably still worth it.