1
1
{-
2
- Copyright 2016 SlamData, Inc.
2
+ Copyright 2017 SlamData, Inc.
3
3
4
4
Licensed under the Apache License, Version 2.0 (the "License");
5
5
you may not use this file except in compliance with the License.
@@ -16,19 +16,107 @@ limitations under the License.
16
16
17
17
module Control.Monad.Fork.Class where
18
18
19
- import Prelude
19
+ import Prelude hiding ( join )
20
20
21
21
import Control.Monad.Aff as Aff
22
- import Control.Monad.Eff.Exception ( Error )
23
- import Control.Monad.Reader.Trans (ReaderT (..))
22
+ import Control.Monad.Error.Class ( class MonadThrow , class MonadError )
23
+ import Control.Monad.Reader.Trans (ReaderT (..), runReaderT )
24
24
import Control.Monad.Trans.Class (lift )
25
25
26
- class Monad m ⇐ MonadFork e m | m → e where
27
- fork ∷ ∀ a . m a → m (e → m Boolean )
26
+ -- | Represents Monads which can be forked asynchronously.
27
+ -- |
28
+ -- | Laws:
29
+ -- |
30
+ -- | ```purescript
31
+ -- | -- Unjoined suspension is a no-op
32
+ -- | suspend a1 *> suspend a2 = suspend a2
33
+ -- |
34
+ -- | -- Suspend/join is identity
35
+ -- | suspend >=> join = id
36
+ -- |
37
+ -- | -- Fork/join is identity
38
+ -- | fork >=> join = id
39
+ -- |
40
+ -- | -- Join is idempotent
41
+ -- | join t *> join t = join t
42
+ -- | ```
43
+ class (Monad m , Functor f ) ⇐ MonadFork f m | m → f where
44
+ suspend ∷ ∀ a . m a → m (f a )
45
+ fork ∷ ∀ a . m a → m (f a )
46
+ join ∷ ∀ a . f a → m a
28
47
29
- instance monadForkAff ∷ MonadFork Error (Aff.Aff eff ) where
30
- fork = map Aff .cancel <<< Aff .forkAff
48
+ instance monadForkAff ∷ MonadFork (Aff.Fiber eff ) (Aff.Aff eff ) where
49
+ suspend = Aff .suspendAff
50
+ fork = Aff .forkAff
51
+ join = Aff .joinFiber
31
52
32
- instance monadForkReaderT ∷ MonadFork e m ⇒ MonadFork e (ReaderT r m ) where
33
- fork (ReaderT ma) =
34
- ReaderT \r → map lift <$> fork (ma r)
53
+ instance monadForkReaderT ∷ MonadFork f m ⇒ MonadFork f (ReaderT r m ) where
54
+ suspend (ReaderT ma) = ReaderT (suspend <<< ma)
55
+ fork (ReaderT ma) = ReaderT (fork <<< ma)
56
+ join = lift <<< join
57
+
58
+ -- | Represents Monads which can be killed after being forked.
59
+ -- |
60
+ -- | Laws:
61
+ -- |
62
+ -- | ```purescript
63
+ -- | -- Killed suspension is an exception
64
+ -- | suspend a >>= \f -> kill e f *> join f = throwError e
65
+ -- |
66
+ -- | -- Suspend/kill is unit
67
+ -- | suspend a >>= kill e = pure unit
68
+ -- | ```
69
+ class (MonadFork f m , MonadThrow e m ) ⇐ MonadKill e f m | m → e f where
70
+ kill ∷ ∀ a . e → f a → m Unit
71
+
72
+ instance monadKillAff ∷ MonadKill Aff.Error (Aff.Fiber eff ) (Aff.Aff eff ) where
73
+ kill = Aff .killFiber
74
+
75
+ instance monadKillReaderT ∷ MonadKill e f m ⇒ MonadKill e f (ReaderT r m ) where
76
+ kill e = lift <<< kill e
77
+
78
+ data BracketCondition e a
79
+ = Completed a
80
+ | Failed e
81
+ | Killed e
82
+
83
+ -- | Represents Monads which support cleanup in the presence of async
84
+ -- | exceptions.
85
+ -- |
86
+ -- | Laws:
87
+ -- | ```purescript
88
+ -- | bracket a k \_ -> pure r
89
+ -- | = uninterruptible (a >>= k (Completed r))
90
+ -- |
91
+ -- | -- Release failed
92
+ -- | bracket a k \_ -> throwError e
93
+ -- | = uninterruptible (a >>= k (Failed e) *> throwError e)
94
+ -- |
95
+ -- | -- Release killed
96
+ -- | fork (bracket a k \_ -> never) >>= \f -> kill e f *> void (try (join f))
97
+ -- | = uninterruptible (a >>= k (Killed e))
98
+ -- | ```
99
+ class (MonadKill e f m , MonadError e m ) ⇐ MonadBracket e f m | m → e f where
100
+ bracket ∷ ∀ r a . m r → (BracketCondition e a → r → m Unit ) → (r → m a ) → m a
101
+ uninterruptible ∷ ∀ a . m a → m a
102
+ never ∷ ∀ a . m a
103
+
104
+ instance monadBracketAff ∷ MonadBracket Aff.Error (Aff.Fiber eff ) (Aff.Aff eff ) where
105
+ bracket acquire release run =
106
+ Aff .generalBracket acquire
107
+ { completed: release <<< Completed
108
+ , failed: release <<< Failed
109
+ , killed: release <<< Killed
110
+ }
111
+ run
112
+ uninterruptible = Aff .invincible
113
+ never = Aff .never
114
+
115
+ instance monadBracketReaderT ∷ MonadBracket e f m ⇒ MonadBracket e f (ReaderT r m ) where
116
+ bracket (ReaderT acquire) release run = ReaderT \r →
117
+ bracket (acquire r)
118
+ (\c a → runReaderT (release c a) r)
119
+ (\a → runReaderT (run a) r)
120
+ uninterruptible k = ReaderT \r ->
121
+ uninterruptible (runReaderT k r)
122
+ never = lift never
0 commit comments