Skip to content

Commit e7ce06a

Browse files
Fix loop (#233)
* Update Apply superclass law * Change ap constraint back to Monad * Port `ap` back to Monad * Reimplement `ap` using bind and pure * Document why revert was needed * Stop importing ap from Bind * Update purescript-psa to v0.8.0 * Update "for any Bind" to "for any Monad" * Update 'Apply - Bind' to 'Apply - Monad'
1 parent 212e486 commit e7ce06a

File tree

4 files changed

+25
-20
lines changed

4 files changed

+25
-20
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
},
88
"devDependencies": {
99
"eslint": "^4.19.1",
10-
"purescript-psa": "^0.6.0",
10+
"purescript-psa": "^0.8.0",
1111
"pulp": "^15.0.0",
1212
"rimraf": "^2.6.2"
1313
}

src/Control/Bind.purs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ module Control.Bind
66
, composeKleisli, (>=>)
77
, composeKleisliFlipped, (<=<)
88
, ifM
9-
, ap
109
, module Data.Functor
1110
, module Control.Apply
1211
, module Control.Applicative
@@ -38,7 +37,7 @@ import Type.Proxy (Proxy(..), Proxy2, Proxy3)
3837
-- | laws:
3938
-- |
4039
-- | - Associativity: `(x >>= f) >>= g = x >>= (\k -> f k >>= g)`
41-
-- | - Apply Superclass: `apply = ap`
40+
-- | - Apply Superclass: `apply f x = f >>= \f’ -> map f’ x`
4241
-- |
4342
-- | Associativity tells us that we can regroup operations which use `do`
4443
-- | notation so that we can unambiguously write, for example:
@@ -149,17 +148,3 @@ infixr 1 composeKleisliFlipped as <=<
149148
-- | ```
150149
ifM :: forall a m. Bind m => m Boolean -> m a -> m a -> m a
151150
ifM cond t f = cond >>= \cond' -> if cond' then t else f
152-
153-
-- | `ap` provides a default implementation of `(<*>)` for any `Bind`, without
154-
-- | using `(<*>)` as provided by the `Apply`-`Bind` superclass relationship.
155-
-- |
156-
-- | `ap` can therefore be used to write `Apply` instances as follows:
157-
-- |
158-
-- | ```purescript
159-
-- | instance applyF :: Apply F where
160-
-- | apply = ap
161-
-- | ```
162-
ap :: forall m a b. Bind m => m (a -> b) -> m a -> m b
163-
ap f a = do
164-
f' <- f
165-
map f' a

src/Control/Monad.purs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module Control.Monad
33
, liftM1
44
, whenM
55
, unlessM
6+
, ap
67
, module Data.Functor
78
, module Control.Apply
89
, module Control.Applicative
@@ -11,7 +12,7 @@ module Control.Monad
1112

1213
import Control.Applicative (class Applicative, liftA1, pure, unless, when)
1314
import Control.Apply (class Apply, apply, (*>), (<*), (<*>))
14-
import Control.Bind (class Bind, bind, ap, ifM, join, (<=<), (=<<), (>=>), (>>=))
15+
import Control.Bind (class Bind, bind, ifM, join, (<=<), (=<<), (>=>), (>>=))
1516

1617
import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>))
1718
import Data.Unit (Unit)
@@ -64,3 +65,22 @@ unlessM :: forall m. Monad m => m Boolean -> m Unit -> m Unit
6465
unlessM mb m = do
6566
b <- mb
6667
unless b m
68+
69+
-- | `ap` provides a default implementation of `(<*>)` for any `Monad`, without
70+
-- | using `(<*>)` as provided by the `Apply`-`Monad` superclass relationship.
71+
-- |
72+
-- | `ap` can therefore be used to write `Apply` instances as follows:
73+
-- |
74+
-- | ```purescript
75+
-- | instance applyF :: Apply F where
76+
-- | apply = ap
77+
-- | ```
78+
-- Note: Only a `Bind` constraint is needed, but this can
79+
-- produce loops when used with other default implementations
80+
-- (i.e. `liftA1`).
81+
-- See https://github.com/purescript/purescript-prelude/issues/232
82+
ap :: forall m a b. Monad m => m (a -> b) -> m a -> m b
83+
ap f a = do
84+
f' <- f
85+
a' <- a
86+
pure (f' a')

src/Prelude.purs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ module Prelude
3030

3131
import Control.Applicative (class Applicative, pure, liftA1, unless, when)
3232
import Control.Apply (class Apply, apply, (*>), (<*), (<*>))
33-
import Control.Bind (class Bind, bind, class Discard, discard, ifM, ap, join, (<=<), (=<<), (>=>), (>>=))
33+
import Control.Bind (class Bind, bind, class Discard, discard, ifM, join, (<=<), (=<<), (>=>), (>>=))
3434
import Control.Category (class Category, identity)
35-
import Control.Monad (class Monad, liftM1, unlessM, whenM)
35+
import Control.Monad (class Monad, liftM1, unlessM, whenM, ap)
3636
import Control.Semigroupoid (class Semigroupoid, compose, (<<<), (>>>))
3737

3838
import Data.Boolean (otherwise)

0 commit comments

Comments
 (0)