I want to modify my state with a function that depends on the old state, but also introduces some randomness. My function f
looks like this:
f :: State -> Eff (random :: RANDOM) State
I guess my state should be pure, and I had no idea how to get rid off Eff
, other than using unsafePerformEff
, so I did this:
eval :: Query ~> H.ComponentDSL State Query g
eval (Tick next) = do
H.modify (unsafePerformEff <<< f)
pure next
This works, but there has to be another, more safe way. I already added the random effect to my main function:
main :: Eff (H.HalogenEffects (random :: RANDOM)) Unit
But how should eval
look like? Maybe modify
does not work here, and there is another way to update state?
Purescript Halogen, side effect (random number) does not work for me, since f
depends on the old state.
modify
itself doesn't let you perform effectful updates, but yes, you can use get
and then modify
(or set
) afterwards to do so. Adapted from the other example with random:
module Main where
import Prelude
import Control.Monad.Aff (Aff)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Random (randomInt, RANDOM)
import Halogen as H
import Halogen.HTML.Events.Indexed as HE
import Halogen.HTML.Indexed as HH
import Halogen.Util (runHalogenAff, awaitBody)
type State = { n :: Int }
initialState :: State
initialState = { n: 3 }
data Query a = NewRandom a
ui :: forall eff. H.Component { n :: Int } Query (Aff (random :: RANDOM | eff))
ui =
H.component { render, eval }
where
render :: State -> H.ComponentHTML Query
render state =
HH.button
[ HE.onClick $ HE.input_ NewRandom ]
[ HH.text $ show state.n ]
eval :: Query ~> H.ComponentDSL State Query (Aff (random :: RANDOM | eff))
eval (NewRandom next) = do
state <- H.get
nextState <- H.fromEff (nextRandom state)
H.set nextState
pure next
nextRandom :: State -> Eff (random :: RANDOM | eff) State
nextRandom { n } = do
nextN <- randomInt (n + 1) (n + 10)
pure { n: nextN }
main :: forall eff. Eff (H.HalogenEffects (random :: RANDOM | eff)) Unit
main =
runHalogenAff do
body <- awaitBody
H.runUI ui initialState body
What could be leading to the type error is this type signature though:
f :: State -> Eff (random :: RANDOM) State
The effect row is closed, meaning it will not unify with any other row, you probably want this instead:
f :: forall eff. State -> Eff (random :: RANDOM | eff) State