Skip to content

Commit a9976fd

Browse files
committed
Add ifM', when', whenM', unless' and unlessM'
1 parent f4cad0a commit a9976fd

File tree

4 files changed

+57
-13
lines changed

4 files changed

+57
-13
lines changed

src/Control/Applicative.purs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@ module Control.Applicative
33
, pure
44
, liftA1
55
, unless
6+
, unless'
67
, when
8+
, when'
79
, module Control.Apply
810
, module Data.Functor
911
) where
1012

1113
import Control.Apply (class Apply, apply, (*>), (<*), (<*>))
14+
import Control.Category ((<<<))
1215

16+
import Data.Boolean (otherwise)
1317
import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>))
18+
import Data.HeytingAlgebra (not)
1419
import Data.Unit (Unit, unit)
1520
import Type.Proxy (Proxy(..))
1621

@@ -64,7 +69,14 @@ when :: forall m. Applicative m => Boolean -> m Unit -> m Unit
6469
when true m = m
6570
when false _ = pure unit
6671

72+
-- | Perform an applicative action lazily when a condition is true.
73+
when' :: forall m a. Applicative m => (a -> Boolean) -> (a -> m Unit) -> a -> m Unit
74+
when' f m a = if f a then m a else pure unit
75+
6776
-- | Perform an applicative action unless a condition is true.
6877
unless :: forall m. Applicative m => Boolean -> m Unit -> m Unit
69-
unless false m = m
70-
unless true _ = pure unit
78+
unless = when <<< not
79+
80+
-- | Perform an applicative action lazily unless a condition is true.
81+
unless' :: forall m a. Applicative m => (a -> Boolean) -> (a -> m Unit) -> a -> m Unit
82+
unless' = when' <<< not

src/Control/Bind.purs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Control.Bind
1212
, composeKleisliFlipped
1313
, (<=<)
1414
, ifM
15+
, ifM'
1516
, module Data.Functor
1617
, module Control.Apply
1718
, module Control.Applicative
@@ -148,3 +149,23 @@ infixr 1 composeKleisliFlipped as <=<
148149
-- | ```
149150
ifM :: forall a m. Bind m => m Boolean -> m a -> m a -> m a
150151
ifM cond t f = cond >>= \cond' -> if cond' then t else f
152+
153+
-- | Similar to `ifM` but for use in cases where one of the monadic actions may
154+
-- | be expensive to compute or be responsible for side effects. As PureScript
155+
-- | is not lazy, the standard `ifM` has to construct both monadic actions
156+
-- | before returning the result, whereas here only the corresponding monadic
157+
-- | action is constructed.
158+
-- |
159+
-- | ```purescript
160+
-- | main :: Effect Unit
161+
-- | main = do
162+
-- | response <- ifM' exists update create user
163+
-- | log response
164+
-- |
165+
-- | where
166+
-- | create :: User -> Effect String
167+
-- | update :: User -> Effect String
168+
-- | exists :: User -> Effect Boolean
169+
-- | ```
170+
ifM' :: forall a b m. Bind m => (a -> m Boolean) -> (a -> m b) -> (a -> m b) -> a -> m b
171+
ifM' cond t f a = cond a >>= \cond' -> if cond' then t a else f a

src/Control/Monad.purs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ module Control.Monad
22
( class Monad
33
, liftM1
44
, whenM
5+
, whenM'
56
, unlessM
7+
, unlessM'
68
, ap
79
, module Data.Functor
810
, module Control.Apply
@@ -12,10 +14,13 @@ module Control.Monad
1214

1315
import Control.Applicative (class Applicative, liftA1, pure, unless, when)
1416
import Control.Apply (class Apply, apply, (*>), (<*), (<*>))
15-
import Control.Bind (class Bind, bind, ifM, join, (<=<), (=<<), (>=>), (>>=))
17+
import Control.Bind (class Bind, bind, join, (<=<), (=<<), (>=>), (>>=), ifM, ifM')
18+
import Control.Category ((>>>))
1619

20+
import Data.HeytingAlgebra (not)
21+
import Data.Function (($))
1722
import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>))
18-
import Data.Unit (Unit)
23+
import Data.Unit (Unit, unit)
1924
import Type.Proxy (Proxy)
2025

2126
-- | The `Monad` type class combines the operations of the `Bind` and
@@ -55,16 +60,22 @@ liftM1 f a = do
5560
-- | Perform a monadic action when a condition is true, where the conditional
5661
-- | value is also in a monadic context.
5762
whenM :: forall m. Monad m => m Boolean -> m Unit -> m Unit
58-
whenM mb m = do
59-
b <- mb
60-
when b m
63+
whenM mb m = ifM mb m $ pure unit
64+
65+
-- | Perform a monadic action lazily when a condition is true, where the conditional
66+
-- | value is also in a monadic context.
67+
whenM' :: forall m a. Monad m => (a -> m Boolean) -> (a -> m Unit) -> a -> m Unit
68+
whenM' mb m = ifM' mb m $ \_ -> pure unit
6169

6270
-- | Perform a monadic action unless a condition is true, where the conditional
6371
-- | value is also in a monadic context.
6472
unlessM :: forall m. Monad m => m Boolean -> m Unit -> m Unit
65-
unlessM mb m = do
66-
b <- mb
67-
unless b m
73+
unlessM mb = whenM $ not <$> mb
74+
75+
-- | Perform a monadic action lazily unless a condition is true, where the conditional
76+
-- | value is also in a monadic context.
77+
unlessM' :: forall m a. Monad m => (a -> m Boolean) -> (a -> m Unit) -> a -> m Unit
78+
unlessM' mb = whenM' $ \x -> mb x >>= not >>> pure
6879

6980
-- | `ap` provides a default implementation of `(<*>)` for any `Monad`, without
7081
-- | using `(<*>)` as provided by the `Apply`-`Monad` superclass relationship.

src/Prelude.purs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ module Prelude
4040
, module Data.Void
4141
) where
4242

43-
import Control.Applicative (class Applicative, pure, liftA1, unless, when)
43+
import Control.Applicative (class Applicative, liftA1, pure, unless, unless', when, when')
4444
import Control.Apply (class Apply, apply, (*>), (<*), (<*>))
45-
import Control.Bind (class Bind, bind, class Discard, discard, ifM, join, (<=<), (=<<), (>=>), (>>=))
45+
import Control.Bind (class Bind, bind, class Discard, discard, ifM, ifM', join, (<=<), (=<<), (>=>), (>>=))
4646
import Control.Category (class Category, identity)
47-
import Control.Monad (class Monad, liftM1, unlessM, whenM, ap)
47+
import Control.Monad (class Monad, ap, liftM1, unlessM, unlessM', whenM, whenM')
4848
import Control.Semigroupoid (class Semigroupoid, compose, (<<<), (>>>))
4949

5050
import Data.Boolean (otherwise)

0 commit comments

Comments
 (0)