Skip to content
This repository was archived by the owner on Aug 4, 2023. It is now read-only.

Commit 841c3c7

Browse files
authored
Add promise flattening and lazy boxing (#8)
1 parent a7432d6 commit 841c3c7

File tree

3 files changed

+38
-15
lines changed

3 files changed

+38
-15
lines changed

src/Web/Promise.purs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@ import Prelude
88

99
import Effect (Effect)
1010
import Effect.Uncurried (mkEffectFn1, mkEffectFn2, runEffectFn1, runEffectFn2)
11-
import Web.Promise.Internal (Promise, reject, resolve)
11+
import Web.Promise.Internal (Promise, reject)
1212
import Web.Promise.Internal as P
1313
import Web.Promise.Rejection (Rejection)
1414

1515
type Executor a = (a -> Effect Unit) -> (Rejection -> Effect Unit) -> Effect Unit
1616

17-
new :: forall a. Executor a -> Effect (Promise a)
17+
class Flatten :: Type -> Type -> Constraint
18+
class Flatten a b | a -> b
19+
20+
instance flattenPromise :: Flatten a b => Flatten (Promise a) b
21+
else instance flattenDone :: Flatten a a
22+
23+
new :: forall a b. Flatten a b => Executor a -> Effect (Promise b)
1824
new k = runEffectFn1 P.new $ mkEffectFn2 \onResolve onReject ->
1925
k (runEffectFn1 onResolve) (runEffectFn1 onReject)
2026

21-
then_ :: forall a b. (a -> Effect (Promise b)) -> Promise a -> Effect (Promise b)
27+
then_ :: forall a b c. Flatten b c => (a -> Effect (Promise b)) -> Promise a -> Effect (Promise c)
2228
then_ k p = runEffectFn2 P.then_ (mkEffectFn1 k) p
2329

2430
catch :: forall a b. (Rejection -> Effect (Promise b)) -> Promise a -> Effect (Promise b)
@@ -27,6 +33,9 @@ catch k p = runEffectFn2 P.catch (mkEffectFn1 k) p
2733
finally :: forall a. (Effect (Promise Unit)) -> Promise a -> Effect (Promise a)
2834
finally = runEffectFn2 P.finally
2935

36+
resolve :: forall a b. Flatten a b => a -> Promise b
37+
resolve = P.resolve
38+
3039
all :: forall a. Array (Promise a) -> Effect (Promise (Array a))
3140
all = runEffectFn1 P.all
3241

src/Web/Promise/Internal.purs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ foreign import data Promise :: Type -> Type
1010

1111
type role Promise representational
1212

13-
foreign import new :: forall a. EffectFn1 (EffectFn2 (EffectFn1 a Unit) (EffectFn1 Rejection Unit) Unit) (Promise a)
13+
foreign import new :: forall a b. EffectFn1 (EffectFn2 (EffectFn1 a Unit) (EffectFn1 Rejection Unit) Unit) (Promise b)
1414

15-
foreign import then_ :: forall a b. EffectFn2 (EffectFn1 a (Promise b)) (Promise a) (Promise b)
15+
foreign import then_ :: forall a b c. EffectFn2 (EffectFn1 a (Promise b)) (Promise a) (Promise c)
1616

1717
foreign import catch :: forall a b. EffectFn2 (EffectFn1 Rejection (Promise b)) (Promise a) (Promise b)
1818

1919
foreign import finally :: forall a. EffectFn2 (Effect (Promise Unit)) (Promise a) (Promise a)
2020

21-
foreign import resolve :: forall a. a -> Promise a
21+
foreign import resolve :: forall a b. a -> Promise b
2222

2323
foreign import reject :: forall a. Rejection -> Promise a
2424

src/Web/Promise/Lazy.purs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ import Data.Newtype (class Newtype)
66
import Data.Traversable (traverse)
77
import Effect (Effect)
88
import Effect.Class (class MonadEffect)
9-
import Effect.Uncurried (mkEffectFn1, runEffectFn1, runEffectFn2)
10-
import Web.Promise (Rejection)
9+
import Effect.Uncurried (mkEffectFn1, mkEffectFn2, runEffectFn1, runEffectFn2)
10+
import Web.Promise (Executor, Rejection)
1111
import Web.Promise.Internal as P
1212

13+
-- | A trivial box that adds a layer between promises to prevent automatic flattening.
14+
data Box a = Box a
15+
1316
-- | A pure `Promise` that has not been executed yet. This type can be used
1417
-- | with `do` syntax.
15-
newtype LazyPromise a = LazyPromise (Effect (P.Promise a))
18+
newtype LazyPromise a = LazyPromise (Effect (P.Promise (Box a)))
1619

1720
derive instance newtypeLazyPromise :: Newtype (LazyPromise a) _
1821

@@ -23,17 +26,21 @@ instance applyLazyPromise :: Apply LazyPromise where
2326
apply = ap
2427

2528
instance applicativeLazyPromise :: Applicative LazyPromise where
26-
pure = LazyPromise <<< pure <<< P.resolve
29+
pure = LazyPromise <<< pure <<< P.resolve <<< Box
2730

2831
instance bindLazyPromise :: Bind LazyPromise where
2932
bind (LazyPromise p) k = LazyPromise do
3033
p' <- p
31-
runEffectFn2 P.then_ (mkEffectFn1 \a -> let (LazyPromise b) = k a in b) p'
34+
runEffectFn2 P.then_ (mkEffectFn1 \(Box a) -> let (LazyPromise b) = k a in b) p'
3235

3336
instance monadLazyPromise :: Monad LazyPromise
3437

3538
instance monadEffectLazyPromise :: MonadEffect LazyPromise where
36-
liftEffect = LazyPromise <<< map P.resolve
39+
liftEffect = LazyPromise <<< map (P.resolve <<< Box)
40+
41+
new :: forall a. Executor a -> LazyPromise a
42+
new k = LazyPromise $ runEffectFn1 P.new $ mkEffectFn2 \onResolve onReject ->
43+
k (runEffectFn1 onResolve <<< Box) (runEffectFn1 onReject)
3744

3845
catch :: forall a b. (Rejection -> LazyPromise b) -> LazyPromise a -> LazyPromise b
3946
catch k (LazyPromise p) = LazyPromise do
@@ -43,14 +50,21 @@ catch k (LazyPromise p) = LazyPromise do
4350
finally :: forall a. LazyPromise Unit -> LazyPromise a -> LazyPromise a
4451
finally (LazyPromise p1) (LazyPromise p2) = LazyPromise do
4552
p2' <- p2
46-
runEffectFn2 P.finally p1 p2'
53+
runEffectFn2 P.finally finalize p2'
54+
where
55+
finalize = do
56+
p1' <- p1
57+
runEffectFn2 P.then_ (mkEffectFn1 \(Box a) -> pure (P.resolve a)) p1'
4758

4859
all :: forall a. Array (LazyPromise a) -> LazyPromise (Array a)
4960
all as = LazyPromise do
5061
as' <- traverse (\(LazyPromise a) -> a) as
51-
runEffectFn1 P.all as'
62+
as'' <- runEffectFn1 P.all as'
63+
runEffectFn2 P.then_ rebox as''
64+
where
65+
rebox = mkEffectFn1 \bs -> pure (P.resolve (Box (map (\(Box b) -> b) bs)))
5266

5367
race :: forall a. Array (LazyPromise a) -> LazyPromise a
5468
race as = LazyPromise do
5569
as' <- traverse (\(LazyPromise a) -> a) as
56-
runEffectFn1 P.race as'
70+
runEffectFn1 P.race as'

0 commit comments

Comments
 (0)