Skip to content

Commit 347b9a6

Browse files
author
Tom Harding
committed
Add Eq, Ord and Semigroup constraints for Record
This commit is to be followed by several others, slowly building up the set of record instances in the prelude by way of RowToList.
1 parent 94ce7ef commit 347b9a6

File tree

6 files changed

+137
-1
lines changed

6 files changed

+137
-1
lines changed

src/Data/Eq.purs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
module Data.Eq
22
( class Eq, eq, (==), notEq, (/=)
33
, class Eq1, eq1, notEq1
4+
5+
, class EqRecord
6+
, eqRecordImpl
47
) where
58

9+
import Data.HeytingAlgebra ((&&))
10+
import Data.Internal.Record (unsafeGet)
11+
import Data.RowList (RLProxy(..))
12+
import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
613
import Data.Unit (Unit)
714
import Data.Void (Void)
15+
import Prim.Row as Row
16+
import Prim.RowList as RL
817

918
-- | The `Eq` type class represents types which support decidable equality.
1019
-- |
@@ -66,3 +75,29 @@ instance eq1Array :: Eq1 Array where
6675

6776
notEq1 :: forall f a. Eq1 f => Eq a => f a -> f a -> Boolean
6877
notEq1 x y = (x `eq1` y) == false
78+
79+
class EqRecord rowlist row focus | rowlist -> focus where
80+
eqRecordImpl :: RLProxy rowlist -> Record row -> Record row -> Boolean
81+
82+
instance eqRecordNil :: EqRecord RL.Nil row focus where
83+
eqRecordImpl _ _ _ = true
84+
85+
instance eqRecordCons
86+
:: ( EqRecord rowlistTail row subfocus
87+
, Row.Cons key focus rowTail row
88+
, IsSymbol key
89+
, Eq focus
90+
)
91+
=> EqRecord (RL.Cons key a rowlistTail) row a where
92+
eqRecordImpl _ ra rb
93+
= unsafeGet' key ra == unsafeGet key rb
94+
&& eqRecordImpl (RLProxy :: RLProxy rowlistTail) ra rb
95+
where key = reflectSymbol (SProxy :: SProxy key)
96+
unsafeGet' = unsafeGet :: String -> Record row -> focus
97+
98+
instance eqRecord
99+
:: ( RL.RowToList row list
100+
, EqRecord list row focus
101+
)
102+
=> Eq (Record row) where
103+
eq = eqRecordImpl (RLProxy :: RLProxy list)

src/Data/Internal/Record.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
exports.unsafeGet = function (key) {
2+
return function (xs) {
3+
return xs[key];
4+
};
5+
};
6+
7+
exports.unsafeInsert = function (key) {
8+
return function (value) {
9+
return function (xs) {
10+
xs[key] = value;
11+
return xs;
12+
};
13+
};
14+
};

src/Data/Internal/Record.purs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module Data.Internal.Record where
2+
3+
-- | *Really* unsafely get a value from a record. You really shouldn't be using
4+
-- | this function unless you know what you're doing.
5+
foreign import unsafeGet :: forall a rs. String -> Record rs -> a
6+
7+
-- | *Really* unsafely insert a value into a record. Again, you really
8+
-- | shouldn't use this function.
9+
foreign import unsafeInsert
10+
:: forall a ra rb
11+
. String
12+
-> a
13+
-> Record ra
14+
-> Record rb

src/Data/Ord.purs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ module Data.Ord
1414
, module Data.Ordering
1515
) where
1616

17-
import Data.Eq (class Eq, class Eq1)
17+
import Data.Eq (class Eq, class Eq1, class EqRecord, (/=))
18+
import Data.Internal.Record (unsafeGet)
1819
import Data.Ord.Unsafe (unsafeCompare)
1920
import Data.Ordering (Ordering(..))
2021
import Data.Ring (class Ring, zero, one, negate)
22+
import Data.RowList (RLProxy(..))
23+
import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
2124
import Data.Unit (Unit)
2225
import Data.Void (Void)
26+
import Prim.Row as Row
27+
import Prim.RowList as RL
2328

2429
-- | The `Ord` type class represents types which support comparisons with a
2530
-- | _total order_.
@@ -168,3 +173,32 @@ class Eq1 f <= Ord1 f where
168173

169174
instance ord1Array :: Ord1 Array where
170175
compare1 = compare
176+
177+
class EqRecord rowlist row focus <= OrdRecord rowlist row focus | rowlist -> focus where
178+
compareImpl :: RLProxy rowlist -> Record row -> Record row -> Ordering
179+
180+
instance ordRecordNil :: OrdRecord RL.Nil row focus where
181+
compareImpl _ _ _ = EQ
182+
183+
instance ordRecordCons
184+
:: ( OrdRecord rowlistTail row subfocus
185+
, Row.Cons key focus rowTail row
186+
, IsSymbol key
187+
, Ord focus
188+
)
189+
=> OrdRecord (RL.Cons key focus rowlistTail) row focus where
190+
compareImpl _ ra rb
191+
= if left /= EQ
192+
then left
193+
else compareImpl (RLProxy :: RLProxy rowlistTail) ra rb
194+
where
195+
key = reflectSymbol (SProxy :: SProxy key)
196+
unsafeGet' = unsafeGet :: String -> Record row -> focus
197+
left = unsafeGet' key ra `compare` unsafeGet' key rb
198+
199+
instance ordRecord
200+
:: ( RL.RowToList row list
201+
, OrdRecord list row focus
202+
)
203+
=> Ord (Record row) where
204+
compare = compareImpl (RLProxy :: RLProxy list)

src/Data/RowList.purs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Data.RowList where
2+
3+
import Prim.RowList (kind RowList)
4+
5+
-- | A proxy to carry information about a rowlist.
6+
data RLProxy (rowlist :: RowList)
7+
= RLProxy

src/Data/Semigroup.purs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
module Data.Semigroup (class Semigroup, append, (<>)) where
22

3+
import Data.Internal.Record (unsafeGet, unsafeInsert)
4+
import Data.RowList (RLProxy(..))
5+
import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
36
import Data.Unit (Unit, unit)
47
import Data.Void (Void, absurd)
8+
import Prim.Row as Row
9+
import Prim.RowList as RL
510

611
-- | The `Semigroup` type class identifies an associative operation on a type.
712
-- |
@@ -33,3 +38,30 @@ instance semigroupArray :: Semigroup (Array a) where
3338

3439
foreign import concatString :: String -> String -> String
3540
foreign import concatArray :: forall a. Array a -> Array a -> Array a
41+
42+
class SemigroupRecord rowlist row subrow focus | rowlist -> subrow focus where
43+
semigroupRecordImpl :: RLProxy rowlist -> Record row -> Record row -> Record subrow
44+
45+
instance semigroupRecordNil :: SemigroupRecord RL.Nil row () focus where
46+
semigroupRecordImpl _ _ _ = {}
47+
48+
instance semigroupRecordCons
49+
:: ( IsSymbol key
50+
, Row.Cons key focus subrowTail subrow
51+
, SemigroupRecord rowlistTail row subrowTail subfocus
52+
, Semigroup focus
53+
)
54+
=> SemigroupRecord (RL.Cons key focus rowlistTail) row subrow focus where
55+
semigroupRecordImpl _ ra rb
56+
= unsafeInsert key
57+
(unsafeGet' key ra <> unsafeGet' key rb)
58+
(semigroupRecordImpl (RLProxy :: RLProxy rowlistTail) ra rb)
59+
where key = reflectSymbol (SProxy :: SProxy key)
60+
unsafeGet' = unsafeGet :: String -> Record row -> focus
61+
62+
instance semigroupRecord
63+
:: ( RL.RowToList row list
64+
, SemigroupRecord list row row focus
65+
)
66+
=> Semigroup (Record row) where
67+
append = semigroupRecordImpl (RLProxy :: RLProxy list)

0 commit comments

Comments
 (0)