|
1 | 1 | module Control.Monad.Aff
|
2 |
| - ( module Internal |
3 |
| - , module Control.Monad.Error.Class |
4 |
| - , liftEff' |
5 |
| - , forkAff |
| 2 | + ( Aff |
| 3 | + , Thread |
| 4 | + , ParAff(..) |
| 5 | + , Canceler(..) |
| 6 | + , nonCanceler |
| 7 | + , makeAff |
| 8 | + , launchAff |
6 | 9 | , runAff
|
| 10 | + , forkAff |
| 11 | + , liftEff' |
| 12 | + , bracket |
| 13 | + , delay |
| 14 | + , finally |
| 15 | + , atomically |
| 16 | + , killThread |
| 17 | + , joinThread |
7 | 18 | ) where
|
8 | 19 |
|
9 | 20 | import Prelude
|
10 |
| -import Control.Monad.Aff.Internal (ASYNC, Aff, Thread, launchAff, unsafeLaunchAff) |
11 |
| -import Control.Monad.Aff.Internal (Aff, ParAff, Thread, Canceler(..), ASYNC, bracket, delay, launchAff, makeAff, nonCanceler, joinThread, killThread) as Internal |
12 |
| -import Control.Monad.Eff (Eff) |
13 |
| -import Control.Monad.Eff.Class (liftEff) |
14 |
| -import Control.Monad.Eff.Exception (Error, EXCEPTION) |
| 21 | +import Control.Alt (class Alt) |
| 22 | +import Control.Alternative (class Alternative) |
| 23 | +import Control.Apply (lift2) |
| 24 | +import Control.Monad.Eff (Eff, kind Effect) |
| 25 | +import Control.Monad.Eff.Class (class MonadEff, liftEff) |
| 26 | +import Control.Monad.Eff.Exception (Error, EXCEPTION, error) |
| 27 | +import Control.Monad.Eff.Ref (newRef, readRef, writeRef) |
| 28 | +import Control.Monad.Eff.Ref.Unsafe (unsafeRunRef) |
15 | 29 | import Control.Monad.Eff.Unsafe (unsafeCoerceEff)
|
16 |
| -import Control.Monad.Error.Class (try) |
17 |
| -import Data.Either (Either) |
| 30 | +import Control.Monad.Error.Class (class MonadError, class MonadThrow, throwError, catchError, try) |
| 31 | +import Control.Monad.Rec.Class (class MonadRec, Step(..)) |
| 32 | +import Control.MonadPlus (class MonadPlus) |
| 33 | +import Control.MonadZero (class MonadZero) |
| 34 | +import Control.Parallel (parSequence_) |
| 35 | +import Control.Parallel.Class (class Parallel) |
| 36 | +import Control.Plus (class Plus, empty) |
| 37 | +import Data.Either (Either(..), isLeft) |
| 38 | +import Data.Function.Uncurried as Fn |
| 39 | +import Data.Maybe (Maybe(..)) |
| 40 | +import Data.Monoid (class Monoid, mempty) |
| 41 | +import Data.Newtype (class Newtype) |
| 42 | +import Data.Time.Duration (Milliseconds(..)) |
| 43 | +import Partial.Unsafe (unsafeCrashWith) |
18 | 44 |
|
19 |
| -liftEff' ∷ ∀ eff a. Eff (exception ∷ EXCEPTION | eff) a → Aff eff a |
20 |
| -liftEff' = liftEff <<< unsafeCoerceEff |
| 45 | +foreign import data Aff ∷ # Effect → Type → Type |
| 46 | + |
| 47 | +instance functorAff ∷ Functor (Aff eff) where |
| 48 | + map = _map |
| 49 | + |
| 50 | +instance applyAff ∷ Apply (Aff eff) where |
| 51 | + apply = ap |
| 52 | + |
| 53 | +instance applicativeAff ∷ Applicative (Aff eff) where |
| 54 | + pure = _pure |
| 55 | + |
| 56 | +instance bindAff ∷ Bind (Aff eff) where |
| 57 | + bind = _bind |
| 58 | + |
| 59 | +instance monadAff ∷ Monad (Aff eff) |
| 60 | + |
| 61 | +instance semigroupAff ∷ Semigroup a ⇒ Semigroup (Aff eff a) where |
| 62 | + append = lift2 append |
| 63 | + |
| 64 | +instance monoidAff ∷ Monoid a ⇒ Monoid (Aff eff a) where |
| 65 | + mempty = pure mempty |
| 66 | + |
| 67 | +instance altAff ∷ Alt (Aff eff) where |
| 68 | + alt a1 a2 = catchError a1 (const a2) |
| 69 | + |
| 70 | +instance plusAff ∷ Plus (Aff eff) where |
| 71 | + empty = throwError (error "Always fails") |
| 72 | + |
| 73 | +instance alternativeAff ∷ Alternative (Aff eff) |
| 74 | + |
| 75 | +instance monadZeroAff ∷ MonadZero (Aff eff) |
| 76 | + |
| 77 | +instance monadPlusAff ∷ MonadPlus (Aff eff) |
| 78 | + |
| 79 | +instance monadRecAff ∷ MonadRec (Aff eff) where |
| 80 | + tailRecM k = go |
| 81 | + where |
| 82 | + go a = do |
| 83 | + res ← k a |
| 84 | + case res of |
| 85 | + Done r → pure r |
| 86 | + Loop b → go b |
| 87 | + |
| 88 | +instance monadThrowAff ∷ MonadThrow Error (Aff eff) where |
| 89 | + throwError = _throwError |
| 90 | + |
| 91 | +instance monadErrorAff ∷ MonadError Error (Aff eff) where |
| 92 | + catchError = _catchError |
| 93 | + |
| 94 | +instance monadEffAff ∷ MonadEff eff (Aff eff) where |
| 95 | + liftEff = _liftEff |
| 96 | + |
| 97 | +newtype ParAff eff a = ParAff (Aff eff a) |
| 98 | + |
| 99 | +derive instance newtypeParAff ∷ Newtype (ParAff eff a) _ |
| 100 | + |
| 101 | +derive newtype instance functorParAff ∷ Functor (ParAff eff) |
| 102 | + |
| 103 | +instance applyParAff ∷ Apply (ParAff eff) where |
| 104 | + apply (ParAff ff) (ParAff fa) = ParAff $ makeAff \k → do |
| 105 | + ref1 ← unsafeRunRef $ newRef Nothing |
| 106 | + ref2 ← unsafeRunRef $ newRef Nothing |
| 107 | + |
| 108 | + t1 ← launchAff do |
| 109 | + f ← try ff |
| 110 | + liftEff do |
| 111 | + ma ← unsafeRunRef $ readRef ref2 |
| 112 | + case ma of |
| 113 | + Nothing → unsafeRunRef $ writeRef ref1 (Just f) |
| 114 | + Just a → k (f <*> a) |
| 115 | + |
| 116 | + t2 ← launchAff do |
| 117 | + a ← try fa |
| 118 | + liftEff do |
| 119 | + mf ← unsafeRunRef $ readRef ref1 |
| 120 | + case mf of |
| 121 | + Nothing → unsafeRunRef $ writeRef ref2 (Just a) |
| 122 | + Just f → k (f <*> a) |
| 123 | + |
| 124 | + pure $ Canceler \err → |
| 125 | + parSequence_ |
| 126 | + [ killThread err t1 |
| 127 | + , killThread err t2 |
| 128 | + ] |
| 129 | + |
| 130 | +instance applicativeParAff ∷ Applicative (ParAff eff) where |
| 131 | + pure = ParAff <<< pure |
21 | 132 |
|
22 |
| -runAff ∷ ∀ eff a. (Either Error a → Eff eff Unit) → Aff eff a → Eff (async ∷ ASYNC | eff) Unit |
| 133 | +instance semigroupParAff ∷ Semigroup a ⇒ Semigroup (ParAff eff a) where |
| 134 | + append = lift2 append |
| 135 | + |
| 136 | +instance monoidParAff ∷ Monoid a ⇒ Monoid (ParAff eff a) where |
| 137 | + mempty = pure mempty |
| 138 | + |
| 139 | +data AltStatus a |
| 140 | + = Pending |
| 141 | + | Completed a |
| 142 | + |
| 143 | +instance altParAff ∷ Alt (ParAff eff) where |
| 144 | + alt = runAlt |
| 145 | + where |
| 146 | + runAlt ∷ ∀ a. ParAff eff a → ParAff eff a → ParAff eff a |
| 147 | + runAlt (ParAff a1) (ParAff a2) = ParAff $ makeAff \k → do |
| 148 | + ref ← unsafeRunRef $ newRef Nothing |
| 149 | + t1 ← launchAff a1 |
| 150 | + t2 ← launchAff a2 |
| 151 | + |
| 152 | + let |
| 153 | + completed ∷ Thread eff a → Either Error a → Aff eff Unit |
| 154 | + completed t res = do |
| 155 | + val ← liftEff $ unsafeRunRef $ readRef ref |
| 156 | + case val, res of |
| 157 | + _, Right _ → do |
| 158 | + killThread (error "Alt ParAff: early exit") t |
| 159 | + liftEff (k res) |
| 160 | + Nothing, _ → |
| 161 | + liftEff $ unsafeRunRef $ writeRef ref (Just res) |
| 162 | + Just res', _ → |
| 163 | + liftEff (k res') |
| 164 | + |
| 165 | + t3 ← launchAff $ completed t2 =<< try (joinThread t1) |
| 166 | + t4 ← launchAff $ completed t1 =<< try (joinThread t2) |
| 167 | + |
| 168 | + pure $ Canceler \err → |
| 169 | + parSequence_ |
| 170 | + [ killThread err t3 |
| 171 | + , killThread err t4 |
| 172 | + , killThread err t1 |
| 173 | + , killThread err t2 |
| 174 | + ] |
| 175 | + |
| 176 | +instance plusParAff ∷ Plus (ParAff e) where |
| 177 | + empty = ParAff empty |
| 178 | + |
| 179 | +instance alternativeParAff ∷ Alternative (ParAff e) |
| 180 | + |
| 181 | +instance parallelAff ∷ Parallel (ParAff eff) (Aff eff) where |
| 182 | + parallel = ParAff |
| 183 | + sequential (ParAff aff) = aff |
| 184 | + |
| 185 | +newtype Thread eff a = Thread |
| 186 | + { kill ∷ Error → Aff eff Unit |
| 187 | + , join ∷ Aff eff a |
| 188 | + } |
| 189 | + |
| 190 | +instance functorThread ∷ Functor (Thread eff) where |
| 191 | + map f (Thread { kill, join }) = Thread { kill, join: f <$> join } |
| 192 | + |
| 193 | +killThread ∷ ∀ eff a. Error → Thread eff a → Aff eff Unit |
| 194 | +killThread e (Thread t) = t.kill e |
| 195 | + |
| 196 | +joinThread ∷ ∀ eff a. Thread eff a → Aff eff a |
| 197 | +joinThread (Thread t) = t.join |
| 198 | + |
| 199 | +newtype Canceler eff = Canceler (Error → Aff eff Unit) |
| 200 | + |
| 201 | +derive instance newtypeCanceler ∷ Newtype (Canceler eff) _ |
| 202 | + |
| 203 | +instance semigroupCanceler ∷ Semigroup (Canceler eff) where |
| 204 | + append (Canceler c1) (Canceler c2) = |
| 205 | + Canceler \err → parSequence_ [ c1 err, c2 err ] |
| 206 | + |
| 207 | +instance monoidCanceler ∷ Monoid (Canceler eff) where |
| 208 | + mempty = nonCanceler |
| 209 | + |
| 210 | +nonCanceler ∷ ∀ eff. Canceler eff |
| 211 | +nonCanceler = Canceler (const (pure unit)) |
| 212 | + |
| 213 | +launchAff ∷ ∀ eff a. Aff eff a → Eff eff (Thread eff a) |
| 214 | +launchAff aff = Fn.runFn6 _launchAff isLeft unsafeFromLeft unsafeFromRight Left Right aff |
| 215 | + |
| 216 | +runAff ∷ ∀ eff a. (Either Error a → Eff eff Unit) → Aff eff a → Eff eff Unit |
23 | 217 | runAff k aff = void $ launchAff $ liftEff <<< k =<< try aff
|
24 | 218 |
|
25 | 219 | forkAff ∷ ∀ eff a. Aff eff a → Aff eff (Thread eff a)
|
26 |
| -forkAff = liftEff <<< unsafeLaunchAff |
| 220 | +forkAff = liftEff <<< launchAff |
| 221 | + |
| 222 | +delay ∷ ∀ eff. Milliseconds → Aff eff Unit |
| 223 | +delay (Milliseconds n) = Fn.runFn2 _delay Right n |
| 224 | + |
| 225 | +liftEff' ∷ ∀ eff a. Eff (exception ∷ EXCEPTION | eff) a → Aff eff a |
| 226 | +liftEff' = liftEff <<< unsafeCoerceEff |
| 227 | + |
| 228 | +finally ∷ ∀ eff a. Aff eff Unit → Aff eff a → Aff eff a |
| 229 | +finally fin a = bracket (pure unit) (const fin) (const a) |
| 230 | + |
| 231 | +atomically ∷ ∀ eff a. Aff eff a → Aff eff a |
| 232 | +atomically a = bracket a (const (pure unit)) pure |
| 233 | + |
| 234 | +foreign import _pure ∷ ∀ eff a. a → Aff eff a |
| 235 | +foreign import _throwError ∷ ∀ eff a. Error → Aff eff a |
| 236 | +foreign import _catchError ∷ ∀ eff a. Aff eff a → (Error → Aff eff a) → Aff eff a |
| 237 | +foreign import _map ∷ ∀ eff a b. (a → b) → Aff eff a → Aff eff b |
| 238 | +foreign import _bind ∷ ∀ eff a b. Aff eff a → (a → Aff eff b) → Aff eff b |
| 239 | +foreign import _delay ∷ ∀ a eff. Fn.Fn2 (Unit → Either a Unit) Number (Aff eff Unit) |
| 240 | +foreign import _liftEff ∷ ∀ eff a. Eff eff a → Aff eff a |
| 241 | +foreign import bracket ∷ ∀ eff a b. Aff eff a → (a → Aff eff Unit) → (a → Aff eff b) → Aff eff b |
| 242 | +foreign import makeAff ∷ ∀ eff a. ((Either Error a → Eff eff Unit) → Eff eff (Canceler eff)) → Aff eff a |
| 243 | + |
| 244 | +foreign import _launchAff |
| 245 | + ∷ ∀ eff a |
| 246 | + . Fn.Fn6 |
| 247 | + (Either Error a → Boolean) |
| 248 | + (Either Error a → Error) |
| 249 | + (Either Error a → a) |
| 250 | + (Error → Either Error a) |
| 251 | + (a → Either Error a) |
| 252 | + (Aff eff a) |
| 253 | + (Eff eff (Thread eff a)) |
| 254 | + |
| 255 | +unsafeFromLeft ∷ ∀ x y. Either x y → x |
| 256 | +unsafeFromLeft = case _ of |
| 257 | + Left a → a |
| 258 | + Right _ → unsafeCrashWith "unsafeFromLeft: Right" |
| 259 | + |
| 260 | +unsafeFromRight ∷ ∀ x y. Either x y → y |
| 261 | +unsafeFromRight = case _ of |
| 262 | + Right a → a |
| 263 | + Left _ → unsafeCrashWith "unsafeFromRight: Left" |
0 commit comments