turion / rhine

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

Threepenny GUI bindings #97

Open ggreif opened 6 years ago

ggreif commented 6 years ago

I have successfully funneled threepenny-gui events as rhine clocks. How would one package up such a thing? Analogously to rhine-gloss I would expect.

turion commented 6 years ago

Yes, that would be a good approach! Can you upload your code somewhere so we can have a look?

Basically, an event source in threepenny should be a rhine clock. I don't understand threepenny well enough to say more, but I'll learn!

ggreif commented 6 years ago

This is what I have now:

{-# language MultiParamTypeClasses, TypeFamilies #-}

module FRP.Rhine.Clock.Threepenny.Event (threepenny) where

import FRP.Rhine.Clock
import Graphics.UI.Threepenny.Core
import Data.Time.Clock (getCurrentTime)
import Control.Concurrent

-- lift threepenny events into a clock
data ThreepennyClock a = ThreepennyClock (Event a)

instance Clock UI (ThreepennyClock a) where
  type Time (ThreepennyClock a) = UTCTime
  type Tag  (ThreepennyClock a) = a

  initClock (ThreepennyClock ev) = do
    initialTime <- liftIO getCurrentTime
    chan <- liftIO newChan
    liftIO $ ev `register` (chan `writeChan`)
    pure
      (     arrM_ (liftIO getCurrentTime) -- TODO: read time from timestamp!
        &&& arrM_ (liftIO (readChan chan))
      , initialTime
      )
  -- TODO: finalisation!!!

instance Semigroup a => Semigroup (ThreepennyClock a) where
  ThreepennyClock l <> ThreepennyClock r = ThreepennyClock (unionWith (<>) l r)

threepenny :: Event a -> ThreepennyClock a
threepenny = ThreepennyClock

It still suffers from the Stdin clock problem I reported recently (which you have fixed in develop).

turion commented 6 years ago

The implementation looks good (except for the small issue you already mentioned which is easy to fix), but conceptually I'm a bit unsure. Especially with this Semigroup instance, although it looks right. The whole point of type-level clocks schedules is missed whenever clocks that can tick at conceptually different times (such as different events) have the same type (e.g. the same event data type). But threepenny doesn't have type-level distinction between different events, and I wouldn't know how to add it without shoehorning it in with a newtype every time.

turion commented 6 years ago

As for finalisation, Rhine doesn't have a good hook for that yet. But that's an issue that we want to solve in dunai on a fundamental level with type state.

ggreif commented 6 years ago

I have implemented a new threepenny (DOM) event "resize", which only applies to a window. So it could get a type-level tag ["window","resize"]. All things considering you'll need to establish a type-level hierarchy reflecting the nesting of DOM objects. I have a recorded BoBKonf2015 talk about something like this.

turion commented 6 years ago

Ah, that sounds good! Is that talk available online somewhere? If it is foreseeable which kinds of events occur in threepenny, we could model all of them with DataKinds.

ggreif commented 6 years ago

Slides + Video: http://bobkonf.de/2015/greif.html

On 7/11/18, Manuel Bärenz notifications@github.com wrote:

Ah, that sounds good! Is that talk available online somewhere? If it is foreseeable which kinds of events occur in threepenny, we could model all of them with DataKinds.

-- You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub: https://github.com/turion/rhine/issues/97#issuecomment-404122014