levant pied
levant pied

Reputation: 4501

How to use guard in Eff monad

The example in Purescript by Example section 8.17 Mutable State:

is a simulate function:

import Prelude

import Control.Monad.Eff (Eff, forE)
import Control.Monad.ST (ST, newSTRef, readSTRef, modifySTRef)

simulate :: forall eff h. Number -> Number -> Int -> Eff (st :: ST h | eff) Number
simulate x0 v0 time = do
  ref <- newSTRef { x: x0, v: v0 }
  forE 0 (time * 1000) \_ -> do
    modifySTRef ref \o ->
      { v: o.v - 9.81 * 0.001
      , x: o.x + o.v * 0.001
      }
    pure unit
  final <- readSTRef ref
  pure final.x

The function itself works fine. Say it needs to be modified to stop movement of the particle at some value of x. This:

import Prelude
import Control.MonadPlus (guard)

import Control.Monad.Eff (Eff, forE)
import Control.Monad.ST (ST, newSTRef, readSTRef, modifySTRef)

simulate :: forall eff h. Number -> Number -> Int -> Eff (st :: ST h | eff) Number
simulate x0 v0 time = do
  ref <- newSTRef { x: x0, v: v0 }
  forE 0 (time * 1000) \_ -> do
    o <- readSTRef ref
    let v = o.v - 9.81 * 0.001
    let x = o.x + o.v * 0.001 
    guard (x < 100.0)
    modifySTRef ref \o ->
      { v: v
      , x: x
      }
    pure unit
  final <- readSTRef ref
  pure final.x

results in the following error:

  No type class instance was found for

    Control.MonadZero.MonadZero (Eff
                                   ( "st" :: ST h3
                                   | eff4
                                   )
                                )
...

Does this mean guard cannot be used in Eff monad at all? How would one write the code with the same intention in idiomatic purescript?

Upvotes: 2

Views: 249

Answers (1)

Phil Freeman
Phil Freeman

Reputation: 4169

You can't use guard, but you can use when, which works with any Monad:

when (x < 100.0) $
  modifySTRef ref \o ->
    { v: v
    , x: x
    }

Upvotes: 3

Related Questions