Skip to content

Commit 3f9a342

Browse files
authored
Merge pull request #18 from purescript/rec-instance-internal-module
Adds a MonadRec instance for ST, introduces an Internal module
2 parents acef60c + 65b6be3 commit 3f9a342

File tree

6 files changed

+139
-122
lines changed

6 files changed

+139
-122
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"package.json"
1818
],
1919
"dependencies": {
20-
"purescript-prelude": "#compiler/0.12"
20+
"purescript-prelude": "#compiler/0.12",
21+
"purescript-tailrec": "#compiler/0.12"
2122
},
2223
"devDependencies": {
2324
"purescript-console": "#compiler/0.12"

src/Control/Monad/ST.js

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/Control/Monad/ST.purs

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,3 @@
1-
module Control.Monad.ST
2-
( kind Region
3-
, ST
4-
, run
5-
, while
6-
) where
1+
module Control.Monad.ST (module Internal) where
72

8-
import Prelude
9-
10-
-- | `ST` is concerned with _restricted_ mutation. Mutation is restricted to a
11-
-- | _region_ of mutable references. This kind is inhabited by phantom types
12-
-- | which represent regions in the type system.
13-
foreign import kind Region
14-
15-
-- | The `ST` type constructor allows _local mutation_, i.e. mutation which
16-
-- | does not "escape" into the surrounding computation.
17-
-- |
18-
-- | An `ST` computation is parameterized by a phantom type which is used to
19-
-- | restrict the set of reference cells it is allowed to access.
20-
-- |
21-
-- | The `run` function can be used to run a computation in the `ST` monad.
22-
foreign import data ST :: Region -> Type -> Type
23-
24-
foreign import map_ :: forall r a b. (a -> b) -> ST r a -> ST r b
25-
26-
foreign import pure_ :: forall r a. a -> ST r a
27-
28-
foreign import bind_ :: forall r a b. ST r a -> (a -> ST r b) -> ST r b
29-
30-
instance functorST :: Functor (ST r) where
31-
map = map_
32-
33-
instance applyST :: Apply (ST r) where
34-
apply = ap
35-
36-
instance applicativeST :: Applicative (ST r) where
37-
pure = pure_
38-
39-
instance bindST :: Bind (ST r) where
40-
bind = bind_
41-
42-
instance monadST :: Monad (ST r)
43-
44-
-- | Run an `ST` computation.
45-
-- |
46-
-- | Note: the type of `run` uses a rank-2 type to constrain the phantom
47-
-- | type `h`, such that the computation must not leak any mutable references
48-
-- | to the surrounding computation. It may cause problems to apply this
49-
-- | function using the `$` operator. The recommended approach is to use
50-
-- | parentheses instead.
51-
foreign import run :: forall a. (forall r. ST r a) -> a
52-
53-
-- | Loop while a condition is `true`.
54-
-- |
55-
-- | `while b m` is ST computation which runs the ST computation `b`. If its
56-
-- | result is `true`, it runs the ST computation `m` and loops. If not, the
57-
-- | computation ends.
58-
foreign import while :: forall r a. ST r Boolean -> ST r a -> ST r Unit
3+
import Control.Monad.ST.Internal (ST, kind Region, run, while) as Internal

src/Control/Monad/ST/Ref.js renamed to src/Control/Monad/ST/Internal.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
"use strict";
22

3+
exports.map_ = function (f) {
4+
return function (a) {
5+
return function () {
6+
return f(a());
7+
};
8+
};
9+
};
10+
11+
exports.pure_ = function (a) {
12+
return function () {
13+
return a;
14+
};
15+
};
16+
17+
exports.bind_ = function (a) {
18+
return function (f) {
19+
return function () {
20+
return f(a())();
21+
};
22+
};
23+
};
24+
25+
exports.run = function (f) {
26+
return f();
27+
};
28+
29+
exports["while"] = function (f) {
30+
return function (a) {
31+
return function () {
32+
while (f()) {
33+
a();
34+
}
35+
};
36+
};
37+
};
38+
339
exports.new = function (val) {
440
return function () {
541
return { value: val };

src/Control/Monad/ST/Internal.purs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
module Control.Monad.ST.Internal where
2+
3+
import Prelude
4+
5+
import Control.Monad.Rec.Class (class MonadRec, Step(..))
6+
import Partial.Unsafe (unsafePartial)
7+
8+
-- | `ST` is concerned with _restricted_ mutation. Mutation is restricted to a
9+
-- | _region_ of mutable references. This kind is inhabited by phantom types
10+
-- | which represent regions in the type system.
11+
foreign import kind Region
12+
13+
-- | The `ST` type constructor allows _local mutation_, i.e. mutation which
14+
-- | does not "escape" into the surrounding computation.
15+
-- |
16+
-- | An `ST` computation is parameterized by a phantom type which is used to
17+
-- | restrict the set of reference cells it is allowed to access.
18+
-- |
19+
-- | The `run` function can be used to run a computation in the `ST` monad.
20+
foreign import data ST :: Region -> Type -> Type
21+
22+
foreign import map_ :: forall r a b. (a -> b) -> ST r a -> ST r b
23+
24+
foreign import pure_ :: forall r a. a -> ST r a
25+
26+
foreign import bind_ :: forall r a b. ST r a -> (a -> ST r b) -> ST r b
27+
28+
instance functorST :: Functor (ST r) where
29+
map = map_
30+
31+
instance applyST :: Apply (ST r) where
32+
apply = ap
33+
34+
instance applicativeST :: Applicative (ST r) where
35+
pure = pure_
36+
37+
instance bindST :: Bind (ST r) where
38+
bind = bind_
39+
40+
instance monadST :: Monad (ST r)
41+
42+
instance monadRecST :: MonadRec (ST r) where
43+
tailRecM f a = do
44+
r <- new =<< f a
45+
while (isDone <$> read r) do
46+
read r >>= case _ of
47+
Loop a' -> do
48+
e <- f a'
49+
void (write e r)
50+
Done b -> pure unit
51+
fromDone <$> read r
52+
where
53+
fromDone :: forall a b. Step a b -> b
54+
fromDone = unsafePartial \(Done b) -> b
55+
56+
isDone = case _ of
57+
Done _ -> true
58+
_ -> false
59+
60+
-- | Run an `ST` computation.
61+
-- |
62+
-- | Note: the type of `run` uses a rank-2 type to constrain the phantom
63+
-- | type `h`, such that the computation must not leak any mutable references
64+
-- | to the surrounding computation. It may cause problems to apply this
65+
-- | function using the `$` operator. The recommended approach is to use
66+
-- | parentheses instead.
67+
foreign import run :: forall a. (forall r. ST r a) -> a
68+
69+
-- | Loop while a condition is `true`.
70+
-- |
71+
-- | `while b m` is ST computation which runs the ST computation `b`. If its
72+
-- | result is `true`, it runs the ST computation `m` and loops. If not, the
73+
-- | computation ends.
74+
foreign import while :: forall r a. ST r Boolean -> ST r a -> ST r Unit
75+
76+
-- | The type `STRef r a` represents a mutable reference holding a value of
77+
-- | type `a`, which can be used with the `ST r` effect.
78+
foreign import data STRef :: Region -> Type -> Type
79+
80+
-- | Create a new mutable reference.
81+
foreign import new :: forall a r. a -> ST r (STRef r a)
82+
83+
-- | Read the current value of a mutable reference.
84+
foreign import read :: forall a r. STRef r a -> ST r a
85+
86+
-- | Update the value of a mutable reference by applying a function
87+
-- | to the current value, computing a new state value for the reference and
88+
-- | a return value.
89+
foreign import modify' :: forall r a b. (a -> { state :: a, value :: b }) -> STRef r a -> ST r b
90+
91+
-- | Modify the value of a mutable reference by applying a function to the
92+
-- | current value.
93+
modify :: forall r a. (a -> a) -> STRef r a -> ST r Unit
94+
modify f = modify' (\s -> { state: f s, value: unit })
95+
96+
-- | Set the value of a mutable reference.
97+
foreign import write :: forall a r. a -> STRef r a -> ST r a

src/Control/Monad/ST/Ref.purs

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,3 @@
1-
module Control.Monad.ST.Ref where
1+
module Control.Monad.ST.Ref (module Internal) where
22

3-
import Prelude
4-
5-
import Control.Monad.ST (ST, kind Region)
6-
7-
-- | The type `STRef r a` represents a mutable reference holding a value of
8-
-- | type `a`, which can be used with the `ST r` effect.
9-
foreign import data STRef :: Region -> Type -> Type
10-
11-
-- | Create a new mutable reference.
12-
foreign import new :: forall a r. a -> ST r (STRef r a)
13-
14-
-- | Read the current value of a mutable reference.
15-
foreign import read :: forall a r. STRef r a -> ST r a
16-
17-
-- | Update the value of a mutable reference by applying a function
18-
-- | to the current value, computing a new state value for the reference and
19-
-- | a return value.
20-
foreign import modify' :: forall r a b. (a -> { state :: a, value :: b }) -> STRef r a -> ST r b
21-
22-
-- | Modify the value of a mutable reference by applying a function to the
23-
-- | current value.
24-
modify :: forall r a. (a -> a) -> STRef r a -> ST r Unit
25-
modify f = modify' (\s -> { state: f s, value: unit })
26-
27-
-- | Set the value of a mutable reference.
28-
foreign import write :: forall a r. a -> STRef r a -> ST r a
3+
import Control.Monad.ST.Internal (STRef, new, read, modify, modify', write) as Internal

0 commit comments

Comments
 (0)