Skip to content

Commit 94c0538

Browse files
authored
STRecord (#9)
1 parent 058cdde commit 94c0538

File tree

4 files changed

+131
-2
lines changed

4 files changed

+131
-2
lines changed

Diff for: bower.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"dependencies": {
2020
"purescript-symbols": "^3.0.0",
2121
"purescript-functions": "^3.0.0",
22-
"purescript-typelevel-prelude": "^2.3.1"
22+
"purescript-typelevel-prelude": "^2.3.1",
23+
"purescript-st": "^3.0.0"
2324
},
2425
"devDependencies": {
2526
"purescript-assert": "^3.0.0"

Diff for: src/Data/Record/ST.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"use strict";
2+
3+
function copyRecord(rec) {
4+
var copy = {};
5+
for (var key in rec) {
6+
if ({}.hasOwnProperty.call(rec, key)) {
7+
copy[key] = rec[key];
8+
}
9+
}
10+
return copy;
11+
}
12+
13+
exports.runSTRecord = function(rec) {
14+
return function() {
15+
return copyRecord(rec());
16+
};
17+
};
18+
19+
exports.freezeSTRecord = function(rec) {
20+
return function() {
21+
return copyRecord(rec);
22+
};
23+
};
24+
25+
exports.thawSTRecord = function(rec) {
26+
return function() {
27+
return copyRecord(rec);
28+
};
29+
};
30+
31+
exports.unsafePeekSTRecord = function(l) {
32+
return function(rec) {
33+
return function() {
34+
return rec[l];
35+
};
36+
};
37+
};
38+
39+
exports.unsafePokeSTRecord = function(l) {
40+
return function(a) {
41+
return function(rec) {
42+
return function() {
43+
rec[l] = a;
44+
};
45+
};
46+
};
47+
};

Diff for: src/Data/Record/ST.purs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
module Data.Record.ST
2+
( STRecord
3+
, freezeSTRecord
4+
, thawSTRecord
5+
, peekSTRecord
6+
, pokeSTRecord
7+
, runSTRecord
8+
, pureSTRecord
9+
) where
10+
11+
import Prelude
12+
13+
import Control.Monad.Eff (Eff, runPure)
14+
import Control.Monad.ST (ST)
15+
import Data.Symbol (class IsSymbol, SProxy, reflectSymbol)
16+
17+
-- | A value of type `STRecord h r` represents a mutable record with fields `r`,
18+
-- | belonging to the state thread `h`.
19+
-- |
20+
-- | Create values of type `STRecord` using `thawSTRecord`.
21+
foreign import data STRecord :: Type -> # Type -> Type
22+
23+
-- | Freeze a mutable record, creating a copy.
24+
foreign import freezeSTRecord :: forall h r eff. STRecord h r -> Eff (st :: ST h | eff) (Record r)
25+
26+
-- | Thaw an immutable record, creating a copy.
27+
foreign import thawSTRecord :: forall h r eff. Record r -> Eff (st :: ST h | eff) (STRecord h r)
28+
29+
-- | Run an ST computation safely, constructing a record.
30+
foreign import runSTRecord :: forall r eff. (forall h. Eff (st :: ST h | eff) (STRecord h r)) -> Eff eff (Record r)
31+
32+
-- | Run an ST computation safely, constructing a record, assuming no other
33+
-- | types of effects.
34+
pureSTRecord :: forall r. (forall h eff. Eff (st :: ST h | eff) (STRecord h r)) -> Record r
35+
pureSTRecord st = runPure (runSTRecord st)
36+
37+
foreign import unsafePeekSTRecord
38+
:: forall a r h eff
39+
. String
40+
-> STRecord h r
41+
-> Eff (st :: ST h | eff) a
42+
43+
-- | Read the current value of a field in a mutable record, by providing a
44+
-- | type-level representative for the label which should be read.
45+
peekSTRecord
46+
:: forall l h a r r1 eff
47+
. RowCons l a r1 r
48+
=> IsSymbol l
49+
=> SProxy l
50+
-> STRecord h r
51+
-> Eff (st :: ST h | eff) a
52+
peekSTRecord l = unsafePeekSTRecord (reflectSymbol l)
53+
54+
foreign import unsafePokeSTRecord
55+
:: forall a r h eff
56+
. String
57+
-> a
58+
-> STRecord h r
59+
-> Eff (st :: ST h | eff) Unit
60+
61+
-- | Modify a record in place, by providing a type-level representative for the label
62+
-- | which should be updated.
63+
pokeSTRecord
64+
:: forall l h a r r1 eff
65+
. RowCons l a r1 r
66+
=> IsSymbol l
67+
=> SProxy l
68+
-> a
69+
-> STRecord h r
70+
-> Eff (st :: ST h | eff) Unit
71+
pokeSTRecord l = unsafePokeSTRecord (reflectSymbol l)

Diff for: test/Main.purs

+11-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ module Test.Main where
33
import Prelude
44

55
import Control.Monad.Eff (Eff)
6-
import Data.Record.Builder as Builder
76
import Data.Record (delete, get, insert, modify, set, equal)
7+
import Data.Record.Builder as Builder
8+
import Data.Record.ST (pokeSTRecord, pureSTRecord, thawSTRecord)
89
import Data.Record.Unsafe (unsafeHas)
910
import Data.Symbol (SProxy(..))
1011
import Test.Assert (ASSERT, assert')
@@ -33,6 +34,15 @@ main = do
3334
assert' "unsafeHas2" $
3435
not $ unsafeHas "b" { a: 42 }
3536

37+
let stTest1 = pureSTRecord do
38+
rec <- thawSTRecord { x: 41, y: "" }
39+
pokeSTRecord x 42 rec
40+
pokeSTRecord y "testing" rec
41+
pure rec
42+
43+
assert' "pokeSTRecord" $
44+
stTest1.x == 42 && stTest1.y == "testing"
45+
3646
let testBuilder = Builder.build (Builder.insert x 42
3747
>>> Builder.merge { y: true, z: "testing" }
3848
>>> Builder.delete y) {}

0 commit comments

Comments
 (0)