-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create a lazy signal that employs an Effect #1
Comments
I guess I would add that I think this would not be an issue if I could call |
A signal must always have a value, even just after construction. With a It is however possible to have functions - -- For pure side effects
execEffect :: Effect Unit -> Signal Unit
execEffect e = step unit do
a <- liftEffect e
pure (step unit empty)
-- Or when you want the return value
runEffect :: forall a. Effect a -> Signal (Maybe a)
runEffect e = step Nothing do
a <- liftEffect e
pure (step (Just a) empty)
-- Or with a supplied initial value instead of using a Maybe
runEffectWithInit :: forall a. a -> Effect a -> Signal a
runEffectWithInit i e = step i do
a <- liftEffect e
pure (step a empty) For |
@ajnsit Thanks, this does look like what I need. But a question: at first I thought |
Basically - |
Ah, I see! I'd been using I'm getting the following type error with the code at the moment:
The new type signature I'm using is: runEffectWithInit :: forall a v. MonadEffect v => a -> Effect a -> Signal v a But I get a similar error:
|
It does work with the concrete type |
To qualify my above comment, when I said it works, it does compile, but the issue of the app hanging still seems to occur, with an out of memory error reported on the browser's console. |
Ah you don't need the MonadEffect here. In the code I posted, I had omitted the view argument to
That's strange, it seems to work for me. Can you show me the code? I also realised that I already have something similar called fireOnce :: forall v a. Monoid v => Widget v a -> Signal v (Maybe a) Which can be used with import Effect.Now (now)
showCurrentInstant = dyn do
name <- justWait
"UNKNOWN"
(fireOnce do liftEffect do map show now)
pure
display $ D.text name |
@ajnsit Ah, I see my error with regard to MonadEffect, should have thought about that more carefully. I added updated code in the stampModifiedTime branch; see diff. This causes the default user experience found in the master branch to break as described. By the way, this might be a good time to mention that this app is getting very close to being useful. I still need to add debouncing to prevent frequent DOM updates, and possibly remove formless as mixing it with continuously updating signals doesn't seem to have much benefit, and does add a few idiosyncrasies with regard to user experience. |
@bbarker I replied to your issue about debouncing. Closing this. Please feel free to reopen if necessary. |
@ajnsit This was actually unrelated to debounce, except that debounce might be used as a way to hack around the issue. My above comment states, perhaps not very directly, that this issue is not yet resolved, and provides a branch that elicits the undesirable behavior of the apparent infinite loop. |
Ah I see, reopening the issue. |
@bbarker Is it possible to have a small independent code snippet that reproduces the problem? |
Deleted previous comment - haven't been able to minimally reproduce yet, as a simple attempt works. Will look more on Monday if not before. |
@ajnsit OK, finally, reproduced the bug in a minimal example! I don't think it is too surprising now that I look at it in this way. It relates to using I think what is needed is something like
val r1: Rx[Char]
val r2: Rx[Int]
val sp: Rx[Int] = r2.sampleOn(r1)
// r1 => u u u u ...
// r2 => 1 2 3 4 ...
// sp => 1 3 3 4 ... This would allow one to have the dateTimeSignal fire only when some other signal, or collection of signals (more generally) would fire. |
@ajnsit I added another commit to show that the firing of the dateTimeWidg :: Widget HTML DateTime
dateTimeWidg = do
liftEffect nowDateTime
dateTimeSig :: Signal HTML DateTime
dateTimeSig = justWait initDate (fireOnce dateTimeWidg) pure
hello :: String -> Signal HTML String
hello s = step s do
greeting <- D.div'
[ "Hello" <$ D.button [P.onClick] [D.text "Say Hello"]
, "Namaste" <$ D.button [P.onClick] [D.text "Say Namaste"]
]
_ <- D.text (greeting <> " Sailor!") <|> D.button [P.onClick] [D.text "restart"]
pure (hello greeting)
outerLoop :: Signal HTML (Maybe DateTime)
outerLoop = loopS Nothing \lastDateMay -> D.div_ [] do
helloOut <- hello "INIT"
dateTime <- dateTimeSig
display $ D.text helloOut
pure $ pure $ dateTime At this time, I'm not entirely sure how to address the issue in Concur, either with existing functionality, or by providing new functionality. |
Thanks @bbarker I will take a look at this soon! |
Hi @ajnsit, I can try to dig into this more, but wanted to see if you've tried it in another implementation of Concur first; seems like that might be useful. |
@bbarker I haven't tried it in another implementation. It would be interesting to see if the issue still manifests with something other than React. Apologies that I haven't had a lot of time to dig into this yet. Will try to get to it. |
@bbarker I have two completely independent backends for Purescript-Concur right now. They are not publically released yet, but I'll check your examples internally and get back to you soon. |
Hi @ajnsit, Just curious if you'd had a chance to check this with either of the other backends yet - if not, do you think either is in a state that is worth giving it a try? |
I came back to this one and tried the following, which worked: genRecIdent :: CtrlSignal HTML (Opt.Option (M.BaseIdRows ()))
genRecIdent oldId = do
let idMay = Opt.get (SProxy :: _ "id") oldId
idMayNew <- case idMay of
Just idOld -> pure $ Just idOld
Nothing -> do
uuid <- runEffectInit UUID.emptyUUID UUID.genUUID
pure $ do
pfx <- urnPrefix
uuidNES <- fromString $ UUID.toString uuid
pure $ pfx <> uuidNES
pure $ execState (do
get >>= Opt.maySetOptState (SProxy :: _ "id") idMayNew
get >>= Opt.maySetOptState (SProxy :: _ "idType") (Just M.URN)
) oldId
where
urnPrefix = fromString "urn:uuid:" This was basically using one of your functions above: runEffectInit :: forall a. a -> Effect a -> Signal HTML a
runEffectInit i e = step i do
a <- liftEffect e
pure (step a empty) So, given that, I thought I could return to the problem at hand and write another similar function, also using dateInput :: CtrlSignal HTML (Either String M.XsdDate)
dateInput iVal = do
iValNesEi <- runEffectInit (runErr iVal) $ dateToNesEi iVal
prevTxt :: String <- pure $ case iValNesEi of
Left _ -> ""
Right dtStr -> toString dtStr
prevErr <- pure $ case iValNesEi of
Left err -> err
Right _ -> ""
txtMay :: Maybe NonEmptyString <- textInput (fromString prevTxt)
display $ case iValNesEi of
Right _ -> mempty
Left err -> errorDisplay $ Just err
case txtMay of
Just txtNE -> runEffectInit (runErr txtNE) $
(lmap show) <$> (EX.try $ MR.parseDate txtNE)
Nothing -> pure $ Left "no date input"
where
dateToNesEi :: Either String DateTime -> Effect (Either String NonEmptyString)
dateToNesEi dtEi = do
let dt = fromMaybe bottom $ hush dtEi
nesEi <- EX.try $ MW.dateTimeToStr dt
pure $ (lmap show) nesEi
runErr :: forall a b. Show a => a -> Either String b
runErr ei = Left $ "Run time date parsing error on " <> (show ei) |
Also, as an additional datapoint, I confirmed that replacing occurrences of |
I'd like to have something like a signal that reads the current date:
The widget seems fine, however, the signal creates an infinite (eagerly evaluated) loop, since
dateTimWidg
returns immediately.Ideally, there would be a way to have
dateTimeSig
only queried when other signals at the same level fire. The particular goal here is that I have user's inputting data to records, but this particular field of the record should be automatically timestamped by the app.The text was updated successfully, but these errors were encountered: