diff --git a/src/Control/Alternative.purs b/src/Control/Alternative.purs index c1b27b3..5bec9c7 100644 --- a/src/Control/Alternative.purs +++ b/src/Control/Alternative.purs @@ -1,5 +1,6 @@ module Control.Alternative ( class Alternative + , guard , module Control.Alt , module Control.Applicative , module Control.Apply @@ -12,6 +13,7 @@ import Control.Applicative (class Applicative, pure, liftA1, unless, when) import Control.Apply (class Apply, apply, (*>), (<*), (<*>)) import Control.Plus (class Plus, empty) +import Data.Unit (Unit, unit) import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) -- | The `Alternative` type class has no members of its own; it just specifies @@ -25,3 +27,24 @@ import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) class (Applicative f, Plus f) <= Alternative f instance alternativeArray :: Alternative Array + +-- | Fail using `Plus` if a condition does not hold, or +-- | succeed using `Applicative` if it does. +-- | +-- | For example: +-- | +-- | ```purescript +-- | import Prelude +-- | import Control.Alternative (guard) +-- | import Data.Array ((..)) +-- | +-- | factors :: Int -> Array Int +-- | factors n = do +-- | a <- 1..n +-- | b <- 1..n +-- | guard $ a * b == n +-- | pure a +-- | ``` +guard :: forall m. Alternative m => Boolean -> m Unit +guard true = pure unit +guard false = empty diff --git a/src/Control/MonadPlus.purs b/src/Control/MonadPlus.purs index 66afbb4..74fdd79 100644 --- a/src/Control/MonadPlus.purs +++ b/src/Control/MonadPlus.purs @@ -12,20 +12,23 @@ module Control.MonadPlus ) where import Control.Alt (class Alt, alt, (<|>)) -import Control.Alternative (class Alternative) +import Control.Alternative (class Alternative, guard) import Control.Applicative (class Applicative, pure, liftA1, unless, when) import Control.Apply (class Apply, apply, (*>), (<*), (<*>)) import Control.Bind (class Bind, bind, ifM, join, (<=<), (=<<), (>=>), (>>=)) import Control.Monad (class Monad, ap, liftM1) -import Control.MonadZero (class MonadZero, guard) +import Control.MonadZero (class MonadZero) import Control.Plus (class Plus, empty) import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) --- | The `MonadPlus` type class has no members of its own but extends --- | `MonadZero` with an additional law: +-- | The `MonadPlus` type class has no members of its own; it just specifies +-- | that the type has both `Monad` and `Alternative` instances. +-- | +-- | Types which have `MonadPlus` instances should also satisfy the following +-- | law: -- | -- | - Distributivity: `(x <|> y) >>= f == (x >>= f) <|> (y >>= f)` -class MonadZero m <= MonadPlus m +class (Monad m, Alternative m) <= MonadPlus m instance monadPlusArray :: MonadPlus Array diff --git a/src/Control/MonadZero.purs b/src/Control/MonadZero.purs index 045f29d..a4749ec 100644 --- a/src/Control/MonadZero.purs +++ b/src/Control/MonadZero.purs @@ -1,6 +1,15 @@ +-- | This module is **deprecated** and will be removed in a future release. +-- | +-- | The annihilation law witnessed by `MonadZero` is trivially satisfied by +-- | lawful monads due to parametricity: while evaluating `empty >>= f`, the +-- | function `f` can’t ever be called, since that would require `empty` to +-- | produce a value, which means that `empty >>= f` must be the same as +-- | `empty >>= pure`, which by the monad laws is just `empty`. +-- | +-- | Use `Monad` and `Alternative` constraints instead. + module Control.MonadZero ( class MonadZero - , guard , module Control.Alt , module Control.Alternative , module Control.Applicative @@ -12,7 +21,7 @@ module Control.MonadZero ) where import Control.Alt (class Alt, alt, (<|>)) -import Control.Alternative (class Alternative) +import Control.Alternative (class Alternative, guard) import Control.Applicative (class Applicative, pure, liftA1, unless, when) import Control.Apply (class Apply, apply, (*>), (<*), (<*>)) import Control.Bind (class Bind, bind, ifM, join, (<=<), (=<<), (>=>), (>>=)) @@ -20,7 +29,8 @@ import Control.Monad (class Monad, ap, liftM1) import Control.Plus (class Plus, empty) import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) -import Data.Unit (Unit, unit) + +import Prim.TypeError (class Warn, Text) -- | The `MonadZero` type class has no members of its own; it just specifies -- | that the type has both `Monad` and `Alternative` instances. @@ -29,28 +39,4 @@ import Data.Unit (Unit, unit) -- | laws: -- | -- | - Annihilation: `empty >>= f = empty` -class (Monad m, Alternative m) <= MonadZero m - -instance monadZeroArray :: MonadZero Array - --- | Fail using `Plus` if a condition does not hold, or --- | succeed using `Monad` if it does. --- | --- | For example: --- | --- | ```purescript --- | import Prelude --- | import Control.Monad (bind) --- | import Control.MonadZero (guard) --- | import Data.Array ((..)) --- | --- | factors :: Int -> Array Int --- | factors n = do --- | a <- 1..n --- | b <- 1..n --- | guard $ a * b == n --- | pure a --- | ``` -guard :: forall m. MonadZero m => Boolean -> m Unit -guard true = pure unit -guard false = empty +class (Monad m, Alternative m, Warn (Text "'MonadZero' is deprecated, use 'Monad' and 'Alternative' constraints instead")) <= MonadZero m