如何在Eff monad中使用守卫

时间:2017-02-15 18:11:18

标签: purescript

Purescript by Example的例子8.17可变状态:

是一个模拟函数:

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

该功能本身运作正常。假设需要修改它以停止粒子移动到x的某个值。这样:

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

导致以下错误:

  No type class instance was found for

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

这是否意味着guard根本不能在Eff monad中使用?如何在惯用的purescript中以相同的意图编写代码?

1 个答案:

答案 0 :(得分:3)

您无法使用guard,但可以使用when,它适用于任何Monad

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