1
votes

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.

1
Okay, I just found Halogen's get and set, but I still get type errors.stholzm

1 Answers

1
votes

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