Giter VIP home page Giter VIP logo

reflex-frp / reflex Goto Github PK

View Code? Open in Web Editor NEW
1.1K 63.0 142.0 2.25 MB

Interactive programs without callbacks or side-effects. Functional Reactive Programming (FRP) uses composable events and time-varying values to describe interactive systems as pure functions. Just like other pure functional code, functional reactive code is easier to get right on the first try, maintain, and reuse.

Home Page: https://reflex-frp.org

License: BSD 3-Clause "New" or "Revised" License

Haskell 97.41% Nix 1.25% C 1.32% Shell 0.02%
haskell reactive reflex-frp functional-reactive-programming frp

reflex's Introduction

Haskell Hackage BSD3 License

Interactive programs without callbacks or side-effects. Functional Reactive Programming (FRP) uses composable events and time-varying values to describe interactive systems as pure functions. Just like other pure functional code, functional reactive code is easier to get right on the first try, maintain, and reuse.

Reflex is a fully-deterministic, higher-order Functional Reactive Programming interface and an engine that efficiently implements that interface.

Visit https://reflex-frp.org for more information, tutorials, documentation and examples.

Resources

Hacking

From the root of a Reflex Platform checkout, run ./scripts/hack-on haskell-overlays/reflex-packages/dep/reflex. This will check out the reflex source code into the haskell-overlays/reflex-packages/dep/reflex directory. You can then point that checkout at your fork, make changes, etc. Use the ./try-reflex or ./scripts/work-on scripts to start a shell in which you can test your changes.

reflex's People

Contributors

3noch avatar alexfmpe avatar ali-abrar avatar aljce avatar bennofs avatar cgibbard avatar dalaing avatar danbornside avatar davean avatar dbbnrl avatar dfordivam avatar elvishjerricco avatar endgame avatar ericson2314 avatar esoeylemez avatar hamishmack avatar jbetz avatar lpsmith avatar luigy avatar maralorn avatar matthewbauer avatar meditans avatar mightybyte avatar oliver-batchelor avatar parenthetical avatar phadej avatar ryantrinkle avatar tomsmalley avatar treeowl avatar xplat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reflex's Issues

cabal install reflex likely to break ghcjs

I have gradually installed ghc 7.10.3 and ghcjs from Github and now I am trying to install reflex. Cabal install reflex gives me the following:

$ cabal install reflex

Resolving dependencies...
In order, the following would be installed:
bifunctors-5.3 (latest: 5.4.1) (via: these-0.6.2.1 semigroupoids-5.0.1 profunctors-5.2) (new version)
dependent-sum-0.3.2.2 (latest: 0.4) (via: reflex-0.4.0 dependent-map-0.2.4.0) (new package)
dependent-map-0.2.4.0 (via: reflex-0.4.0) (new package)
exception-transformers-0.4.0.5 (via: reflex-0.4.0) (new package)
haskell-src-exts-1.17.1 (latest: 1.19.1) (via: reflex-0.4.0 haskell-src-meta-0.6.0.14) (new version)
haskell-src-meta-0.6.0.14 (latest: 0.7.0.1) (via: reflex-0.4.0) (new version)
profunctors-5.2 (via: these-0.6.2.1) (reinstall) (changes: bifunctors-5.4.1 -> 5.3)
ref-tf-0.4.0.1 (via: reflex-0.4.0) (new package)
semigroupoids-5.0.1 (latest: 5.1) (via: these-0.6.2.1) (new version)
these-0.6.2.1 (latest: 0.7.3) (via: reflex-0.4.0) (new package)
reflex-0.4.0 (new package)

cabal: The following packages are likely to be broken by the reinstalls:
lens-4.15.1
ghcjs-0.2.0
free-4.12.4
kan-extensions-5.0.1
adjunctions-4.3
Use --force-reinstalls if you want to install anyway.

Terminal says I am going to break lens, adjunctions as well as ghcjs itself. Is there any work-around?

SVG not rendered properly

If you create html with these contents:

<!DOCTYPE html>
<html><head><style>html, body { margin: 0; padding: 0; }
</style></head>
  <body><svg baseprofile="full" height="200px" version="1.1" viewbox="0 0 300 200" width="300px" xmlns="http://www.w3.org/2000/svg"><rect fill="red" height="100%" width="100%"></rect><circle cx="150" cy="100" fill="green" r="80"></circle><text fill="white" font-size="60" text-anchor="middle" x="150" y="125">SVG</text></svg></body></html>

You'll see something like this: https://i.imgur.com/Kv9VJcW.png

If you write a program which builds similar HTML with reflex:

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE OverloadedLists #-}

module Main where

import           Data.FileEmbed
import           Reflex.Dom

main :: IO ()
main = mainWidgetWithCss $(embedFile "style.css") atompit

atompit :: MonadWidget t m => m ()
atompit = do
  elAttr "svg" [ ("version", "1.1")
               , ("baseProfile", "full")
               , ("width", "300px")
               , ("height", "200px")
               , ("xmlns", "http://www.w3.org/2000/svg")
               , ("viewBox", "0 0 300 200")] $ do
    elAttr "rect" [("width", "100%"), ("height", "100%"), ("fill", "red")] (return ())
    elAttr "circle" [("cx", "150"), ("cy", "100"), ("r", "80"), ("fill", "green")] (return ())
    elAttr "text" [("x", "150"), ("y", "125"), ("font-size", "60"), ("text-anchor", "middle"), ("fill", "white")] $ text "SVG"

You'll see this: https://i.imgur.com/HrfflPh.png

I don't understand why Chrome renders same DOM tree, but doesn't render SVG well. Maybe you've seen this before already? Thanks.

Define Dynamic in terms of Incremental?

Since Dynamic is a specific case of Increment, would it make sense to define Dynamic in terms of Incremental? Or are there performance problems that I did not think of?

type Dynamic t a = Incremental t (Identity a)

`t` type parameter and time travel

Just started looking at Reflex and blown away thus far!

I've been looking for a FRP implementation to use in neuroscience, modeling electrode voltage as Behavior and action potentials (voltage "spike") as Events. After a spike occuring at time t1, it needs to be classified to a particular neuron based on the behavior of the electrode on the interval (t1-0.005,t1+0.005).

As I understand Conal Elliott's original specification, this is possible in classic FRP. Is there natural way to do time travel and intervals in Reflex? I'm a bit fuzzy on the timeline t in Reflex, but it seems like this is the place to implement time travel.

Thanks for making this library available!

Cleanup resources of never-occurring root events

Problem

I would like that when a root event's trigger is garbage collected, that this root is removed from the event network, no longer reclaiming any resources (it should act just as if it was never).
This is currently not the case, since it'll still consume memory in the parents list of any merges it is registered in and there will be an IORef for saving its occurence (which we know will always be Nothing), just to name a few examples. This optimization should be safe because there is no way to ever trigger a firing of the event again if the trigger was collected.

Why would this be useful?

Consider the following situation. You want to use reflex with a framework that supports objects.
objects are just values that have some members and some associated reflex events (for example, there is an event when a member of the object is changed by the framework). Further, let's assume that the lifetime of the object depends on the framework and you cannot control that: for example, if the object is passed to JavaScript, events can be generated as long as JavaScript has a reference to it, because JavaScript can change members of the object which will trigger a reflex event.

For the example, it suffices to consider a simpler case: we only need objects that have exactly one member, and we will restrict that member to be of type Int, so there'll also be only event for the object: Event t Int, that fires whenever that single member if changed by JavaScript code.

Now, I would like to expose the following function to work with the framework from reflex:

createObject :: (Reflex t, MonadFramework t m) => Event t Int -> m (Event t (Event t Int))

This function will create a new object whenever the input event fires with a new initial value for the object member. Creating a new object will also fire the output event, containing the Event for observing the changes to the member of the newly created object.

The framework provides us with a way to execute some haskell code when the object is garbage collected (last reference dropped) in JavaScript. We then know that the event which createObject returned when it created the object can never fire again, so we would like it not to retain any resources. This is currently not the case, since it'll consume memory in the parents list of any merges it is registered in and there will be an IORef for saving its occurence (which we know will always be Nothing), just to name a few examples.

Semantics/Documentation of `switchPromptly` on switchover misleading

Does the switchPromptly result fire if a) the old event fires b) the new event fires c) either fires?

Current docs say

-- | Switches to the new event whenever it receives one; the new event is used
-- immediately, on the same frame that it is switched to

which suggests b), but the current implementation is c).

Update dependencies so that Nix can install reflex

Reflex and reflex-dom are awesome. We want to use them in production. The trouble is, the only way I've found of successfully installing GHCJS + reflex/reflex-dom is to use try-reflex. Trying to install reflex via vanilla Nix (ie. no try-reflex) fails, since reflex's dependencies are not available in any Nix channel (nor are they even available in any nixpkgs revision, judging by the dozens of version shims in try-reflex).

It's great that we can try reflex using try-reflex, but obviously that's not really fit for production. In order to use reflex in production we need a sane installation story that Just Works™ with the rest of the project.

Given that Nix appears to be the leading solution right now for "Making GHC and GHCJS Just Work™", making reflex/reflex-dom work with Nix would be ideal, IMHO. If there was a version of reflex/reflex-dom that worked with the NixOS-15.09 channel for example, it would make our Haskell Everywhere™ dreams come true.

Feature request: onDemand :: IO a -> Behavior x a

The point is to be able to run use a cheap IO a function to create a Behavior t a, which would lazily obtain current values whenever any event requires it. I see this question has been answered on stackoverflow from time to time, so I wonder what is the current state of the things?

I've been trying to workaround this for a while and came up with a seems-to-be-not-crashing solution. I posted it as an answer to one discussion.
Here is how it looks like:

import System.IO.Unsafe (unsafeInterleaveIO)
import qualified Reflex.Spider.Internal as Spider

onDemand :: IO a -> Behavior t a
onDemand ma = SpiderBehavior . Spider.Behavior . Spider.BehaviorM . ReaderT $ computeF
  where
    {-# NOINLINE computeF #-}
    computeF (Nothing, _) = unsafeInterleaveIO ma
    computeF (Just (invW,_), _) = unsafeInterleaveIO $ do
        toReconnect <- newIORef []
        _ <- Spider.invalidate toReconnect [invW]
        ma

So, the idea is to call invalidate function (with unsafeInterleaveIO) on current state as late as possible every time the value is requested.

Now, the question is if this code breaks something internally or not? :)
Related questions:

  • Is the list inside toReconnect always empty in current setting?
  • Is the returned WeakList of invalidators going to be empty in current setting in future?

Excessive develop memory consumption comparing to 0.4.0

Maybe it mostly comes from reflex-dom but I'm not quite sure how to trace it down properly.
Here is a PR porting minimalistic example to 0.5.0 - qrilka/reflex-huge-table#1
I was using mostly Chrome task manager to check RAM consumption and running make open and then clicking "go" button showed the following result:

  • in master version (using reflex-0.4.0) initially page consumed around 28M and after button click consumed RAM jumped to 60M then after some time it decreased to 43M and was almost stable showing numbers from 43M to 44M

  • in reflex-0.5.0 branch initially page was about 37M. After button click it jumped to 181M and didn't stop there and kept increasing up to 227M. Then probably some GC happened and memory shrunk to 152M. After that it wasn't quite stable and was showing numbers from that 152M up to 180M

Also I have used Chrome developer tools and took heap snapshots on initial page state and after table rendering.

branch inital snapshot size initial "Object" snapshot after click "Object" after click
master 9.4M 4113 (4%) 21.5M 153495 (58%)
reflex-0.5.0 12.7M 5662(4%) 115M 544847(76%)

Probably the way I build table in that example is not quite optimal (any advice on better way to do it?) but the main point is different run-time characteristics of the same code built with the same GHCJS running in the same Chrome but using different reflex and reflex-dom versions.

Please let me know how could I help debugging this issue further.

Causality loop found

Hi there!

I just hit the following with my app:

Causality loop found
CallStack (from HasCallStack):
  error, called at src/Reflex/Spider/Internal.hs:1609:19 in reflex-0.5.0-CCOIUV1qeMZE5bAytzHgn3:Reflex.Spider.Internal

I don't know yet whether this is a bug in reflex or in my application. What things can cause this error? What should I watch out for?

Thank you!

Best regards,

Robert

Examples or high level documentation

Hi! Thanks for your work! This looks really interesting. I'm looking for info on how to experiment with reflex in an OpenGL environment. More documentation and examples would be greatly appreciated. I'm guessing reflex can be used outside of a DOM environment and I'd like to explore that. Thanks again!

Build failure on nixpkgs master

The build fails on nixpkgs master thusly:

desktop@steamos:~/src/reflex-glfw$ nsr /nix/store/csc1glcas5ch21hrbn626l3hbaip8jsi-reflex-0.5.0.drv
these derivations will be built:
  /nix/store/csc1glcas5ch21hrbn626l3hbaip8jsi-reflex-0.5.0.drv
building path(s) ‘/nix/store/ar422r10ydmwl7jzmninl9q790wf1c17-reflex-0.5.0’
setupCompilerEnvironmentPhase
Build with /nix/store/zd8z7wq30fycyz76kmxh46ix6z1r1w7w-ghc-8.0.2.
unpacking sources
unpacking source archive /nix/store/n9fi7k0i1in9axbl0hil3sr42zklax9l-reflex-0f5b87d14ef4cf048d41657638b5976524c41fa6-src
source root is reflex-0f5b87d14ef4cf048d41657638b5976524c41fa6-src
patching sources
compileBuildDriverPhase
setupCompileFlags: -package-db=/tmp/nix-build-reflex-0.5.0.drv-4/package.conf.d -j4 -threaded
[1 of 1] Compiling Main             ( Setup.hs, /tmp/nix-build-reflex-0.5.0.drv-4/Main.o )
Linking Setup ...
configuring
configureFlags: --verbose --prefix=/nix/store/ar422r10ydmwl7jzmninl9q790wf1c17-reflex-0.5.0 --libdir=$prefix/lib/$compiler --libsubdir=$pkgid --with-gcc=gcc --package-db=/tmp/nix-build-reflex-0.5.0.drv-4/package.conf.d --ghc-option=-optl=-Wl,-rpath=/nix/store/ar422r10ydmwl7jzmninl9q790wf1c17-reflex-0.5.0/lib/ghc-8.0.2/reflex-0.5.0 --ghc-option=-j4 --disable-split-objs --disable-library-profiling --disable-profiling --enable-shared --disable-coverage --enable-library-vanilla --enable-executable-dynamic --enable-tests --ghc-option=-split-sections
Configuring reflex-0.5.0...
Setup: Encountered missing dependencies:
haskell-src-exts >=1.16 && <1.18, haskell-src-meta ==0.6.*
note: keeping build directory ‘/tmp/nix-build-reflex-0.5.0.drv-4’
builder for ‘/nix/store/csc1glcas5ch21hrbn626l3hbaip8jsi-reflex-0.5.0.drv’ failed with exit code 1
error: build of ‘/nix/store/csc1glcas5ch21hrbn626l3hbaip8jsi-reflex-0.5.0.drv’ failed

Reflex doesn't build with dependent-map-0.2

[1 of 8] Compiling Data.Functor.Misc ( src/Data/Functor/Misc.hs, dist/build/Data/Functor/Misc.js_o )

src/Data/Functor/Misc.hs:42:42:
    Expecting one more argument to ‘DMap (WrapArg m f)’
    Expected a type, but ‘DMap (WrapArg m f)’ has kind ‘(* -> *) -> *’
    In the type signature for ‘sequenceDmap’:
      sequenceDmap :: (Monad m, GCompare f) =>
                      DMap (WrapArg m f) -> m (DMap f)

src/Data/Functor/Misc.hs:46:101:
    Expecting one more argument to ‘DMap (WrapArg g f)’
    Expected a type, but ‘DMap (WrapArg g f)’ has kind ‘(* -> *) -> *’
    In the type signature for ‘combineDMapsWithKey’:
      combineDMapsWithKey :: forall f g h i. GCompare f =>
                             (forall a. f a -> These (g a) (h a) -> i a)
                             -> DMap (WrapArg g f) -> DMap (WrapArg h f) -> DMap (WrapArg i f)

src/Data/Functor/Misc.hs:56:37:
    Expecting one more argument to ‘DMap k’
    Expected a type, but ‘DMap k’ has kind ‘(k0 -> *) -> *’
    In the type signature for ‘wrapDMap’:
      wrapDMap :: (forall a. a -> f a) -> DMap k -> DMap (WrapArg f k)

src/Data/Functor/Misc.hs:59:41:
    Expecting one more argument to ‘DMap (WrapArg f k)’
    Expected a type, but ‘DMap (WrapArg f k)’ has kind ‘(* -> *) -> *’
    In the type signature for ‘rewrapDMap’:
      rewrapDMap :: (forall a. f a -> g a)
                    -> DMap (WrapArg f k) -> DMap (WrapArg g k)

src/Data/Functor/Misc.hs:62:39:
    Expecting one more argument to ‘DMap (WrapArg f k)’
    Expected a type, but ‘DMap (WrapArg f k)’ has kind ‘(* -> *) -> *’
    In the type signature for ‘unwrapDMap’:
      unwrapDMap :: (forall a. f a -> a) -> DMap (WrapArg f k) -> DMap k

src/Data/Functor/Misc.hs:65:50:
    Expecting one more argument to ‘DMap (WrapArg f k)’
    Expected a type, but ‘DMap (WrapArg f k)’ has kind ‘(* -> *) -> *’
    In the type signature for ‘unwrapDMapMaybe’:
      unwrapDMapMaybe :: (forall a. f a -> Maybe a)
                         -> DMap (WrapArg f k) -> DMap k

src/Data/Functor/Misc.hs:68:25:
    Expecting one more argument to ‘DMap (Const2 k v)’
    Expected a type, but ‘DMap (Const2 k v)’ has kind ‘(* -> *) -> *’
    In the type signature for ‘mapToDMap’:
      mapToDMap :: Map k v -> DMap (Const2 k v)

src/Data/Functor/Misc.hs:71:40:
    Expecting one more argument to ‘DMap (WrapArg f (Const2 k v))’
    Expected a type,
      but ‘DMap (WrapArg f (Const2 k v))’ has kind ‘(* -> *) -> *’
    In the type signature for ‘mapWithFunctorToDMap’:
      mapWithFunctorToDMap :: Map k (f v)
                              -> DMap (WrapArg f (Const2 k v))

src/Data/Functor/Misc.hs:74:14:
    Expecting one more argument to ‘DMap (Const2 k v)’
    Expected a type, but ‘DMap (Const2 k v)’ has kind ‘(* -> *) -> *’
    In the type signature for ‘dmapToMap’:
      dmapToMap :: DMap (Const2 k v) -> Map k v

joinE missing

I propose a joinE combinator for flattening events out of dyn, even it's provided from DOM it's a Reflex only code to solve it

joinE
:: (Reflex t, MonadHold t f) =>
Event t (Event t a) -> f (Event t a)
joinE = fmap switch . hold never

patchThatChangesAndSortsMapWith creates patches with Just undefined as target keys

FunctorMaybe

I feel like FunctorMaybe isn't the most useful typeclass. It's got one instance, and that let's us call things like ffilter on Events. It seems like it would be better to just have functions filterEvent and filterMapEvent instead of ffilter and fforMaybe. They would be more monomorphic and more understandable.

Memory leak with non-firing event

The code below, when executed with +RTS -T, displays the current memory usage (in KiB) together with a counter that can be incremented by typing any character. The memory usage keeps constantly increasing, but is reset whenever the counter is incremented by typing (i.e. triggering the counterEv event). I have observed the following characteristics:

  • Sampling counter in debugStr (in a pull) causes the leak.
  • Sampling counter in the host monad does not cause the leak.
  • The leaked memory is released every time counterEv fires, changing the value of counter.

{-# LANGUAGE BangPatterns #-}

module Main where

import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Ref
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
import Data.Dependent.Sum
import Data.Maybe
import GHC.Stats
import Reflex
import Reflex.Host.Class
import System.IO
import System.Mem
import Text.Printf


getMemUsed :: (MonadIO m) => m Integer
getMemUsed =
    liftIO $ do
        performGC
        toInteger . currentBytesUsed <$> getGCStats


main :: IO ()
main =
    runSpiderHost $ do
        liftIO $ do
            hSetBuffering stdin NoBuffering
            hSetEcho stdin False

        (memUsedEv, memUsedRef) <- newEventWithTriggerRef
        memUsed <- do mu0 <- getMemUsed; runHostFrame (hold mu0 memUsedEv)

        (counterEv, counterRef) <- newEventWithTriggerRef
        counter <- runHostFrame (hold (0 :: Integer) counterEv)

        debugStr <- runHostFrame $ do
            pure . pull $
                printf "%8.3fk %8d"
                <$> fmap (\mu -> fromInteger mu / 1024 :: Double) (sample memUsed)
                <*> sample counter

        forever $ do
            mCounterVal <- runMaybeT $ do
                trig <- MaybeT (readRef counterRef)
                liftIO (hReady stdin) >>= guard
                liftIO getChar
                !c <- (+ 1) <$> lift (sample counter)
                pure (trig ==> c)

            mMemUsedVal <- runMaybeT $ do
                trig <- MaybeT (readRef memUsedRef)
                mu' <- lift (sample memUsed)
                mu <- getMemUsed
                guard (mu /= mu')
                pure (trig ==> mu)

            fireEvents (catMaybes [mCounterVal, mMemUsedVal])

            s <- runHostFrame (sample debugStr)
            liftIO $ do
                hPutStr stderr ('\r' : s ++ "\027[K")
                hFlush stderr

Please consider joining stackage

Hi Ryan,

this is a standard request of mine with projects I use, or which I add to Debian:

Please consider adding your package to Stackage. Essentially, this gives you free QA and early feedback when something breaks, i.e. before your users notice. It does not require you to use Stackage or stack yourself. See http://www.stackage.org/authors for details.

Greetings,
Joachim

Default instance for Dynamic

It would be nice to have a Default instance for Dynamic without having to define an orphan. It would be the simple passthrough instance:

instance Default a => Dynamic t a where
    def = constDyn def

Is this something you would be open to? It's not a huge problem, but would be nice to have when calling functions like this one https://github.com/reflex-frp/reflex-dom-semui/blob/master/src/Reflex/Dom/SemanticUI/Button.hs#L172 where you typically will be passing several constDyn def parameters.

heightBagRemove error

I'm trying to create a Navigation/Router in Reflex.
I'm using a Dynamic t State that I want to read and update recursively while I move between pages (every page should be able to use and update that State).
The code builds (with commit 50d298c), but fails with an error:

main :: MonadWidget t m => m ()
main = do
    rec
        dRoute  <- value <$> textInput def
        dPage   <- mapDyn (router dState) dRoute
        eWidget <- dyn dPage
        dWidget <- holdDyn (constDyn def) eWidget
        let dState = joinDyn dWidget
        display dState
    return()
    where
        router :: MonadWidget t m => Dynamic t State -> Text -> m (Dynamic t State)
        router dState "Page1" = text "Hello from Page1" >> return dState
        router dState _       = text "Otherwise" >> return dState

the error:
heightBagRemove: Height 1 not present in bag HeightBag {_heightBag_size = 2, _heightBag_contents = fromList [(0,1)]}
CallStack (from HasCallStack):
error, called at src/Reflex/Spider/Internal.hs:637:14 in reflex-0.5.0-CudEVeFTJAH8ajDdcbYxWR:Reflex.Spider.Internal

Is there a better way? am I abusing the rec-do notation?

behaviour behaviour problems

I have reduced some problem down to the following testcase, based on reflex HEAD and reflex-host HEAD. the four tests below (one of which is uncommented) highlight the problem. The first fires on either event (which is expected, but not desired). All three remaining cases should (i think) behave the same, but they don't. 2 and 3 show the same "broken" behaviour, while 4 shows the expected behaviour.

(My goal is to have a Dynamic which holds values from one event but fires according only to another event. But 2/3/4 behaving differently seems to be the underlying fundamental issue.)

module Main where
-- brittany @ module --columns=100



import qualified Reflex as R
import qualified Reflex.Host.App as RH
import           Control.Monad (void, forever)
import           Control.Concurrent (threadDelay, forkIO)
import           Control.Monad.IO.Class (liftIO)

import           Lens.Micro ((<&>))



main :: IO ()
main = R.runSpiderHost $ RH.hostApp $ do

  (counterE, counterT) <- RH.newExternalEvent
  _                    <- RH.performPostBuild $ do
    void $ liftIO $ forkIO $ forever $ do
      _ <- counterT ()
      threadDelay 1000000

  counterDyn           <- R.count counterE

  (delayedE, delayedH) <- RH.newExternalEvent
  RH.performEvent_ $ R.updated counterDyn <&> \i -> liftIO $ void $ delayedH (i :: Int)

  _beh2 <- R.hold 0 delayedE

  -- ONE
  ---- works:               (produces 01,12,23,34,..    as expected)
  -- outDyn1 <- R.zipDynWith const <$> R.holdDyn 0 delayedE <*> R.holdDyn () counterE
  -- RH.performEvent_ $ R.updated outDyn1 <&> \x -> liftIO $ print x
  
  -- TWO
  ---- does not work:       (produces 0,0,0,0,0,0..    expected 0,1,2,3..)
  -- let outE = R.tag _beh2 counterE
  -- RH.performEvent_ $ outE <&> \x -> liftIO $ print x
  
  -- THREE
  ---- does not work either (produces 0,0,0,0,0,0..    expected 0,1,2,3,..)
  -- outDyn' <- R.foldDynM (\_ _ -> R.sample _beh2) 0 delayedE
  -- RH.performEvent_ $ R.updated outDyn' <&> \x -> liftIO $ print x

  -- FOUR
  ---- works:               (produces 0,1,2,3.. as expected)
  let outE = R.switch $ _beh2 <&> (<$ counterE)
  RH.performEvent_ $ outE <&> \x -> liftIO $ print x


  -- RH.performEvent_ $ counterE <&> \_ -> liftIO $ putStrLn "counterE"
  RH.performEvent_ $ delayedE <&> \i -> liftIO $ putStrLn $ "delayedE " ++ show i

Report Dynamic-based causality loops better

When a causality loop is created by joining a Dynamic whose contents depend on itself, reflex reports this as

<interactive>: heightBagRemove: Height 1 not present in bag HeightBag {_heightBag_size = 2, _heightBag_contents = fromList [(0,1)]}
CallStack (from HasCallStack):
  error, called at src/Reflex/Spider/Internal.hs:1015:14 in reflex-0.5.0-4m111lPPOvPBxxVtye35C3:Reflex.Spider.Internal

Ideally, it should report this as a causality loop explicitly, instead.

Here's some code that exhibits the problem:

{-# LANGUAGE RecursiveDo #-}

import Control.Monad
import Reflex.Dom

main = mainWidget $ do
  postBuild <- getPostBuild
  rec dd <- holdDyn (constDyn ()) (d <$ postBuild)
      let d = join dd
  performEvent_ $ return <$> updated d

Poor performance with SVG and listWithKey

Doug asked me to post this even with the state the code is currently in (which is far from optimal), so here goes...

My code is in https://github.com/gergoerdi/tfb-reflex-repro and to reproduce it, just do a stack build in that directory, then navigate to the resulting index.html. (You'll need to edit the path in Main.hs because that's how hacked-together the source is at the moment).

If you then click on the Play button, everything works as expected, until the pace picks up and there are lots of rectangles flying around. That's when the framerate goes to crap really fast.

For comparison, I have the original Elm implementation running on http://unsafePerform.io/projects/tfb/ (but that one uses an HTML Canvas instead of SVG -- I'm not sure if that difference matters).

Any migration guide 0.4 -> 0.5?

I was trying to port our app and e.g. stumbled on dissapeared elWith' currently. It would be helpful to have some guidelines for the migration.
Thanks

Installing reflex-0.5.0 fails with "Kind incompatibility when matching types" in Patch.hs

GHCJS Version: 0.2.0 (GHC 7.10.3).
GHCJS Download date: 2017-03-27.
I deleted directory /home/roland/.ghcjs and re-installed the GHCJS compiler.
Clone date of https://github.com/reflex-frp/reflex: 2017-03-27.

File reflex-ghcjs.txt contains the full installation log.

Error:

src/Reflex/Patch.hs:106:45:
Kind incompatibility when matching types:
g0 :: k -> *
Constant () :: * -> *
Expected type: k1 v1 -> ComposeMaybe v v1 -> Maybe (g0 v1)
Actual type: k1 v1 -> ComposeMaybe v v1 -> Maybe (Constant () b0)
Relevant bindings include
deletions :: DMap k1 g0 (bound at src/Reflex/Patch.hs:106:11)
old :: PatchTarget (PatchDMap k1 v)
(bound at src/Reflex/Patch.hs:104:26)
diff :: DMap k1 (ComposeMaybe v)
(bound at src/Reflex/Patch.hs:104:20)
apply :: PatchDMap k1 v
-> PatchTarget (PatchDMap k1 v)
-> Maybe (PatchTarget (PatchDMap k1 v))
(bound at src/Reflex/Patch.hs:104:3)
In the first argument of ‘DMap.mapMaybeWithKey’, namely
‘(const $ nothingToJust . getComposeMaybe)’
In the expression:
DMap.mapMaybeWithKey (const $ nothingToJust . getComposeMaybe) diff
In an equation for ‘deletions’:
deletions
= DMap.mapMaybeWithKey
(const $ nothingToJust . getComposeMaybe) diff

src/Reflex/Patch.hs:384:79:
The second argument of ‘Constant’ should have kind ‘*’,
but ‘a’ has kind ‘k’
In the type signature for ‘deleteFunc’:
deleteFunc :: forall a.
k a -> DMapEdit k v a -> Maybe (Constant () a)
In an equation for ‘apply’:
apply (PatchDMapWithMove p) old
= Just $! insertions DMap.union (old DMap.difference deletions)
where
insertions = DMap.mapMaybeWithKey insertFunc p
insertFunc :: forall a. k a -> DMapEdit k v a -> Maybe (v a)
insertFunc _
= \case {
DMapEdit_Insert _ v -> Just v
DMapEdit_Move _ k -> DMap.lookup k old
DMapEdit_Delete _ -> Nothing }
deletions = DMap.mapMaybeWithKey deleteFunc p
....
In the instance declaration for ‘Patch (PatchDMapWithMove k v)’
cabal: Leaving directory '.'
cabal: Error: some packages failed to install:
reflex-0.5.0 failed during the building phase. The exception was:
ExitFailure 1

Why is Dynamic not an instance of functor and applicative?

Hello

Reflex looks very interesting. I'd go as far as to say that it's among the most exciting things that has happened to FRP since Conals push and pull paper.

I was playing with the try-reflex tutorial. I attempted to modify a part of the tutorial program into this:

nx <- numberInput
d <- dropdown "*" (constDyn ops) def
ny <- numberInput
op <- mapDyn stringToOp $ _dropdown_value d
result <- op <$> nx <*> ny

But it turns out that dynamic is not an instance of neither functor nor applicative? Why not? There is both mapDyn and constDyn?

Upstream `simpleSortableList`

Upstream simpleSortableList from here and add documentation.

-- | Provides a framework for building sortable content in such a way that resorting it can
-- cause minimal disruption. For example, naively resorting a list of images would destroy
-- every image and add them back in the new order. This framework is able to avoid that by
-- preserving the identity of each image and simply moving it to the new location.
simpleSortableList :: forall t m k v. (MonadHold t m, MonadFix m, MonadAdjust t m, Ord k)
                   => (k -> v -> m ()) -- ^ A function to render the content for a key/value in a @Map@
                   -> Map k v -- ^ A @Map@ of values identified by keys
                   -> Event t (v -> v -> Ordering) -- ^ An event carrying a sort function that can resort without destroying/rebuilding each element
                   -> Event t (v -> v -> Ordering) -- ^ An event carrying a sort function that requires a resorting to rebuild each element
                   -> m ()
simpleSortableList f m0 resortFunc resortSlowFunc = do
  rec let resortPatchFast = attachWith (flip patchThatSortsMapWith) (currentIncremental m) resortFunc
          redrawPatch :: Map k v -> (v -> v -> Ordering) -> PatchMapWithMove k v
          redrawPatch d cmp = unsafePatchMapWithMove $ fmap (MapEdit_Insert False) $ Map.fromList $ zip (Map.keys d) (sortBy cmp $ Map.elems d)
          resortPatchSlow = attachWith redrawPatch (currentIncremental m) resortSlowFunc
          resortPatch = leftmost
            [ resortPatchFast
            , resortPatchSlow
            ]
      m <- holdIncremental m0 resortPatch
  _ <- mapMapWithAdjustWithMove f m0 resortPatch
  return ()

Include a helper function to move a MonadHold to the outside of a dynamic.

The weird type signature is required because m1 must be PushM and m.

f :: forall t m a. (Reflex t, MonadHold t m) => (forall m1. (MonadHold t m1) => Dynamic t (m1 a)) -> m (Dynamic t a)
f d = do
    let events = updated d & pushAlways id
    _initial <- sample $ current d
    initial <- _initial
    holdDyn initial events

synchronous version of TriggerEventT

Looks like there isn't a version of TriggerEventT that uses synchronous triggering (yet). Do you accept pull requests for this?

(context: I work on libs that concern animation / gaming, so having synchronous versions would be nice)

Should Patch have a diff method?

Should Patch have a diff method? Should a new typeclass be created? Or is this function useless?

class Patch p where
    ...
    diff :: PatchTarget p -> PatchTarget p -> Maybe p

Causality loop found, cause is weird.

Hi there!

I managed to find the cause of the causality loop found error and was also able to fix it, but I don't understand why this fixes anything. I changed the following code:

    let
      cFamilyName = fmap (fromMaybe "") . runMaybeT $ do
        cId <- MaybeT $ family'^.selectedFamily
        families' <- MaybeT $ family'^.families
        cFamily  <- MaybeT . pure $ families'^.at cId
        pure $ Gonimo.familyName . Db.familyName $ cFamily

to

    let
      getFamilyName :: Maybe FamilyId -> Maybe (Map FamilyId Db.Family) -> Text
      getFamilyName Nothing _ = ""
      getFamilyName _ Nothing = ""
      getFamilyName (Just fid) (Just families') = families'^.at fid._Just.to Db.familyName . to Gonimo.familyName

      cFamilyName = zipDynWith getFamilyName (family'^.selectedFamily) (family'^.families)

the error disappears/appears reproducible. I am 100% certain that this piece of code causes the bug. I just switched from a monadic solution to zipDynWith. I assume they should be equivalent?

I have a workaround with zipDynWith, so this is not critical, but I would like to understand why the monadic version causes causality loop found.

Thanks!

stack overflow on ghcjs --interactive

$ ghcjs --interactive
GHCJSi, version 0.2.0-7.10.3: http://www.github.com/ghcjs/ghcjs/  :? for help
Prelude> 4+45
49
Prelude> import Reflex.Dom
Prelude Reflex.Dom> mainWidget $ el "div" $ text "foo"
*** Exception: stack overflow

See also ghcjs/ghcjs#500

ghcjs base 4.9 support

Hi

I've installed the current stable haskell platform and built ghcjs. This used v4.9 of the base libraries, which is not supported by reflex. Are there any plans to support this in the near future?

Cheers
Gautham

The state of 0.5 version?

I think it (version 0.5) is in the master for some time already but I have seen no plans or roadmap - are there any?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.