Skip to content

Commit de404c2

Browse files
committed
Merge pull request #57 from ethul/topic/rwst-monad-rec
Topic/rwst monad rec
2 parents a4aa3a3 + 4aef7bd commit de404c2

File tree

7 files changed

+105
-51
lines changed

7 files changed

+105
-51
lines changed

docs/Control/Monad/RWS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ to the `Identity` monad.
1414
#### `rws`
1515

1616
``` purescript
17-
rws :: forall r w s a. (r -> s -> See s a w) -> RWS r w s a
17+
rws :: forall r w s a. (r -> s -> RWSResult s a w) -> RWS r w s a
1818
```
1919

2020
Create an action in the `RWS` monad from a function which uses the
@@ -23,7 +23,7 @@ global context and state explicitly.
2323
#### `runRWS`
2424

2525
``` purescript
26-
runRWS :: forall r w s a. RWS r w s a -> r -> s -> See s a w
26+
runRWS :: forall r w s a. RWS r w s a -> r -> s -> RWSResult s a w
2727
```
2828

2929
Run a computation in the `RWS` monad.
@@ -47,7 +47,7 @@ Run a computation in the `RWS` monad, discarding the result
4747
#### `mapRWS`
4848

4949
``` purescript
50-
mapRWS :: forall r w1 w2 s a1 a2. (See s a1 w1 -> See s a2 w2) -> RWS r w1 s a1 -> RWS r w2 s a2
50+
mapRWS :: forall r w1 w2 s a1 a2. (RWSResult s a1 w1 -> RWSResult s a2 w2) -> RWS r w1 s a1 -> RWS r w2 s a2
5151
```
5252

5353
Change the types of the result and accumulator in a `RWS` action

docs/Control/Monad/RWS/Trans.md

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,26 @@
22

33
This module defines the reader-writer-state monad transformer, `RWST`.
44

5-
#### `See`
5+
#### `RWSResult`
66

77
``` purescript
8-
type See s a w = { state :: s, result :: a, log :: w }
9-
```
10-
11-
#### `mkSee`
12-
13-
``` purescript
14-
mkSee :: forall s a w. (Monoid w) => s -> a -> w -> See s a w
8+
data RWSResult state result writer
9+
= RWSResult state result writer
1510
```
1611

1712
#### `RWST`
1813

1914
``` purescript
2015
newtype RWST r w s m a
21-
= RWST (r -> s -> m (See s a w))
16+
= RWST (r -> s -> m (RWSResult s a w))
2217
```
2318

2419
The reader-writer-state monad transformer, which combines the operations
2520
of `ReaderT`, `WriterT` and `StateT` into a single monad transformer.
2621

2722
##### Instances
2823
``` purescript
29-
instance functorRWST :: (Functor m) => Functor (RWST r w s m)
24+
instance functorRWST :: (Functor m, Monoid w) => Functor (RWST r w s m)
3025
instance applyRWST :: (Bind m, Monoid w) => Apply (RWST r w s m)
3126
instance bindRWST :: (Bind m, Monoid w) => Bind (RWST r w s m)
3227
instance applicativeRWST :: (Monad m, Monoid w) => Applicative (RWST r w s m)
@@ -38,12 +33,13 @@ instance monadStateRWST :: (Monad m, Monoid w) => MonadState s (RWST r w s m)
3833
instance monadWriterRWST :: (Monad m, Monoid w) => MonadWriter w (RWST r w s m)
3934
instance monadRWSRWST :: (Monad m, Monoid w) => MonadRWS r w s (RWST r w s m)
4035
instance monadErrorRWST :: (MonadError e m, Monoid w) => MonadError e (RWST r w s m)
36+
instance monadRecRWST :: (Monoid w, MonadRec m) => MonadRec (RWST r w s m)
4137
```
4238

4339
#### `runRWST`
4440

4541
``` purescript
46-
runRWST :: forall r w s m a. RWST r w s m a -> r -> s -> m (See s a w)
42+
runRWST :: forall r w s m a. RWST r w s m a -> r -> s -> m (RWSResult s a w)
4743
```
4844

4945
Run a computation in the `RWST` monad.
@@ -67,7 +63,7 @@ Run a computation in the `RWST` monad, discarding the result.
6763
#### `mapRWST`
6864

6965
``` purescript
70-
mapRWST :: forall r w1 w2 s m1 m2 a1 a2. (m1 (See s a1 w1) -> m2 (See s a2 w2)) -> RWST r w1 s m1 a1 -> RWST r w2 s m2 a2
66+
mapRWST :: forall r w1 w2 s m1 m2 a1 a2. (m1 (RWSResult s a1 w1) -> m2 (RWSResult s a2 w2)) -> RWST r w1 s m1 a1 -> RWST r w2 s m2 a2
7167
```
7268

7369
Change the result and accumulator types in a `RWST` monad action.

src/Control/Monad/RWS.purs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ type RWS r w s = RWST r w s Identity
2626

2727
-- | Create an action in the `RWS` monad from a function which uses the
2828
-- | global context and state explicitly.
29-
rws :: forall r w s a. (r -> s -> See s a w) -> RWS r w s a
29+
rws :: forall r w s a. (r -> s -> RWSResult s a w) -> RWS r w s a
3030
rws f = RWST \r s -> return $ f r s
3131

3232
-- | Run a computation in the `RWS` monad.
33-
runRWS :: forall r w s a. RWS r w s a -> r -> s -> See s a w
33+
runRWS :: forall r w s a. RWS r w s a -> r -> s -> RWSResult s a w
3434
runRWS m r s = runIdentity $ runRWST m r s
3535

3636
-- | Run a computation in the `RWS` monad, discarding the final state
@@ -42,7 +42,7 @@ execRWS :: forall r w s a. RWS r w s a -> r -> s -> Tuple s w
4242
execRWS m r s = runIdentity $ execRWST m r s
4343

4444
-- | Change the types of the result and accumulator in a `RWS` action
45-
mapRWS :: forall r w1 w2 s a1 a2. (See s a1 w1 -> See s a2 w2) -> RWS r w1 s a1 -> RWS r w2 s a2
45+
mapRWS :: forall r w1 w2 s a1 a2. (RWSResult s a1 w1 -> RWSResult s a2 w2) -> RWS r w1 s a1 -> RWS r w2 s a2
4646
mapRWS f = mapRWST (runIdentity >>> f >>> Identity)
4747

4848
-- | Change the type of the context in a `RWS` action

src/Control/Monad/RWS/Trans.purs

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,102 @@
11
-- | This module defines the reader-writer-state monad transformer, `RWST`.
22

3-
module Control.Monad.RWS.Trans
4-
( See(), mkSee
3+
module Control.Monad.RWS.Trans
4+
( RWSResult(..)
55
, RWST(..), runRWST, evalRWST, execRWST, mapRWST, withRWST
66
, module Control.Monad.Trans
77
, module Control.Monad.RWS.Class
88
) where
99

1010
import Prelude
1111

12+
import Data.Either
1213
import Data.Monoid
1314
import Data.Tuple
1415

15-
import Control.Monad.Trans
1616
import Control.Monad.Eff.Class
1717
import Control.Monad.Error.Class
18+
import Control.Monad.RWS.Class
19+
import Control.Monad.Rec.Class
1820
import Control.Monad.Reader.Class
19-
import Control.Monad.Writer.Class
2021
import Control.Monad.State.Class
21-
import Control.Monad.RWS.Class
22-
23-
type See s a w =
24-
{ state :: s
25-
, result :: a
26-
, log :: w
27-
}
22+
import Control.Monad.Trans
23+
import Control.Monad.Writer.Class
2824

29-
mkSee :: forall s a w. (Monoid w) => s -> a -> w -> See s a w
30-
mkSee s a w = { state: s, result: a, log: w }
25+
data RWSResult state result writer = RWSResult state result writer
3126

3227
-- | The reader-writer-state monad transformer, which combines the operations
3328
-- | of `ReaderT`, `WriterT` and `StateT` into a single monad transformer.
34-
newtype RWST r w s m a = RWST (r -> s -> m (See s a w))
29+
newtype RWST r w s m a = RWST (r -> s -> m (RWSResult s a w))
3530

3631
-- | Run a computation in the `RWST` monad.
37-
runRWST :: forall r w s m a. RWST r w s m a -> r -> s -> m (See s a w)
32+
runRWST :: forall r w s m a. RWST r w s m a -> r -> s -> m (RWSResult s a w)
3833
runRWST (RWST x) = x
3934

4035
-- | Run a computation in the `RWST` monad, discarding the final state.
4136
evalRWST :: forall r w s m a. (Monad m) => RWST r w s m a -> r -> s -> m (Tuple a w)
42-
evalRWST m r s = runRWST m r s >>= \see -> return (Tuple see.result see.log)
37+
evalRWST m r s = runRWST m r s >>= \(RWSResult _ result writer) -> return (Tuple result writer)
4338

4439
-- | Run a computation in the `RWST` monad, discarding the result.
4540
execRWST :: forall r w s m a. (Monad m) => RWST r w s m a -> r -> s -> m (Tuple s w)
46-
execRWST m r s = runRWST m r s >>= \see -> return (Tuple see.state see.log)
41+
execRWST m r s = runRWST m r s >>= \(RWSResult state _ writer) -> return (Tuple state writer)
4742

4843
-- | Change the result and accumulator types in a `RWST` monad action.
49-
mapRWST :: forall r w1 w2 s m1 m2 a1 a2. (m1 (See s a1 w1) -> m2 (See s a2 w2)) -> RWST r w1 s m1 a1 -> RWST r w2 s m2 a2
44+
mapRWST :: forall r w1 w2 s m1 m2 a1 a2. (m1 (RWSResult s a1 w1) -> m2 (RWSResult s a2 w2)) -> RWST r w1 s m1 a1 -> RWST r w2 s m2 a2
5045
mapRWST f m = RWST \r s -> f $ runRWST m r s
5146

5247
-- | Change the context type in a `RWST` monad action.
5348
withRWST :: forall r1 r2 w s m a. (r2 -> s -> Tuple r1 s) -> RWST r1 w s m a -> RWST r2 w s m a
5449
withRWST f m = RWST \r s -> uncurry (runRWST m) (f r s)
5550

56-
instance functorRWST :: (Functor m) => Functor (RWST r w s m) where
57-
map f m = RWST \r s -> (\see -> see{result = f see.result}) <$> runRWST m r s
51+
instance functorRWST :: (Functor m, Monoid w) => Functor (RWST r w s m) where
52+
map f m = RWST \r s -> (\(RWSResult state result writer) -> RWSResult state (f result) writer) <$> runRWST m r s
5853

5954
instance applyRWST :: (Bind m, Monoid w) => Apply (RWST r w s m) where
6055
apply f m = RWST \r s ->
61-
runRWST f r s >>= \{state = s', result = f', log = w'} ->
62-
runRWST m r s' <#> \{state = s'', result = a'', log = w''} ->
63-
mkSee s'' (f' a'') (w' ++ w'')
56+
runRWST f r s >>= \(RWSResult s' f' w') ->
57+
runRWST m r s' <#> \(RWSResult s'' a'' w'') ->
58+
RWSResult s'' (f' a'') (w' ++ w'')
6459

6560
instance bindRWST :: (Bind m, Monoid w) => Bind (RWST r w s m) where
6661
bind m f = RWST \r s ->
67-
runRWST m r s >>= \{result = a, state = s', log = l} ->
68-
runRWST (f a) r s' <#> \see' ->
69-
see' { log = l ++ see'.log }
62+
runRWST m r s >>= \(RWSResult s' a w) ->
63+
runRWST (f a) r s' <#> \(RWSResult state result writer) ->
64+
RWSResult state result (w ++ writer)
7065

7166
instance applicativeRWST :: (Monad m, Monoid w) => Applicative (RWST r w s m) where
72-
pure a = RWST \_ s -> pure $ mkSee s a mempty
67+
pure a = RWST \_ s -> pure $ RWSResult s a mempty
7368

7469
instance monadRWST :: (Monad m, Monoid w) => Monad (RWST r w s m)
7570

7671
instance monadTransRWST :: (Monoid w) => MonadTrans (RWST r w s) where
77-
lift m = RWST \_ s -> m >>= \a -> return $ mkSee s a mempty
72+
lift m = RWST \_ s -> m >>= \a -> return $ RWSResult s a mempty
7873

7974
instance monadEffRWS :: (Monad m, Monoid w, MonadEff eff m) => MonadEff eff (RWST r w s m) where
8075
liftEff = lift <<< liftEff
8176

8277
instance monadReaderRWST :: (Monad m, Monoid w) => MonadReader r (RWST r w s m) where
83-
ask = RWST \r s -> pure $ mkSee s r mempty
78+
ask = RWST \r s -> pure $ RWSResult s r mempty
8479
local f m = RWST \r s -> runRWST m (f r) s
8580

8681
instance monadStateRWST :: (Monad m, Monoid w) => MonadState s (RWST r w s m) where
87-
state f = RWST \_ s -> case f s of Tuple a s' -> pure $ mkSee s' a mempty
82+
state f = RWST \_ s -> case f s of Tuple a s' -> pure $ RWSResult s' a mempty
8883

8984
instance monadWriterRWST :: (Monad m, Monoid w) => MonadWriter w (RWST r w s m) where
90-
writer (Tuple a w) = RWST \_ s -> pure $ { state: s, result: a, log: w }
91-
listen m = RWST \r s -> runRWST m r s >>= \{ state: s', result: a, log: w} -> pure { state: s', result: Tuple a w, log: w }
92-
pass m = RWST \r s -> runRWST m r s >>= \{ result: Tuple a f, state: s', log: w} -> pure { state: s', result: a, log: f w }
85+
writer (Tuple a w) = RWST \_ s -> pure $ RWSResult s a w
86+
listen m = RWST \r s -> runRWST m r s >>= \(RWSResult s' a w) -> pure $ RWSResult s' (Tuple a w) w
87+
pass m = RWST \r s -> runRWST m r s >>= \(RWSResult s' (Tuple a f) w) -> pure $ RWSResult s' a (f w)
9388

9489
instance monadRWSRWST :: (Monad m, Monoid w) => MonadRWS r w s (RWST r w s m)
9590

9691
instance monadErrorRWST :: (MonadError e m, Monoid w) => MonadError e (RWST r w s m) where
9792
throwError e = lift (throwError e)
9893
catchError m h = RWST $ \r s -> catchError (runRWST m r s) (\e -> runRWST (h e) r s)
94+
95+
instance monadRecRWST :: (Monoid w, MonadRec m) => MonadRec (RWST r w s m) where
96+
tailRecM k a = RWST \r s -> tailRecM (k' r) (RWSResult s a mempty)
97+
where
98+
k' r (RWSResult state result writer) = do
99+
RWSResult state' result' writer' <- runRWST (k result) r state
100+
return case result' of
101+
Left a -> Left (RWSResult state' a (writer <> writer'))
102+
Right b -> Right (RWSResult state' b (writer <> writer'))

test/Example/RWS.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// module Example.RWS
2+
3+
exports.t = function(){
4+
return new Date().valueOf();
5+
};

test/Example/RWS.purs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
module Example.RWS where
2+
3+
import Prelude
4+
5+
import Control.Monad.Eff
6+
import Control.Monad.Eff.Console
7+
import Control.Monad.RWS
8+
import Control.Monad.RWS.Trans
9+
import Control.Monad.Rec.Class
10+
import Control.Monad.State
11+
import Control.Monad.State.Trans
12+
import Control.Monad.Writer
13+
14+
import Data.Either
15+
import Data.Identity
16+
17+
loop :: Int -> RWST String (Array String) Int Identity Unit
18+
loop n = tailRecM go n
19+
where
20+
go 0 = do
21+
tell [ "Done!" ]
22+
return (Right unit)
23+
go n = do
24+
x <- get
25+
put (x + 1)
26+
return (Left (n - 1))
27+
28+
loopState :: Int -> StateT Int Identity Unit
29+
loopState n = tailRecM go n
30+
where
31+
go 0 = do
32+
return (Right unit)
33+
go n = do
34+
x <- get
35+
put (x + 1)
36+
return (Left (n - 1))
37+
38+
main = do
39+
t1 <- t
40+
res1 <- pure $ runIdentity (runRWST (loop 1000000) "" 0)
41+
t2 <- t
42+
print $ "RWST: " ++ show (t2 - t1)
43+
t3 <- t
44+
res2 <- pure $ execState (loopState 1000000) 0
45+
t4 <- t
46+
print $ "StateT: " ++ show (t4 - t3)
47+
48+
foreign import t :: forall eff. Eff eff Number

test/Test/Main.purs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ main = do
99
Example.State.main
1010
Example.StateEff.main
1111
Example.Writer.main
12+
Example.RWS.main

0 commit comments

Comments
 (0)