2017-02-15 33 views
1

Пример в Purescript по примеру раздела 8.17 изменяемое состояние:Как использовать охранника в Eff монады

функция имитации:

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 монады вообще? Как написать код с тем же намерением в идиоматическом пирескопе?

ответ

2

Вы не можете использовать guard, но вы можете использовать when, который работает с любым Monad:

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

Отлично, спасибо Phil! –

0

Функция when не работает на моем компьютере, и это мое решение.

_ <- modifySTRef ref (if cond then func else id)