@@ -26,7 +26,7 @@ module Rel8.Tabulate
2626 , difference
2727 , aggregateTabulation
2828 , orderTabulation
29− , singularize
29+ , distinctTabulation
3030 , optionalTabulation
3131 , manyTabulation
3232 , someTabulation
@@ -48,13 +48,14 @@ import Rel8.Expr ( Expr )
4848import Rel8.Order ( Order )
4949import Rel8.Query ( Query )
5050import Rel8.Query.Aggregate ( aggregate )
51+import Rel8.Query.Distinct ( distinctOn )
5152import Rel8.Query.Exists ( withBy, withoutBy )
5253import Rel8.Query.Filter ( filter, where_ )
5354import Rel8.Query.Maybe ( optional )
5455import Rel8.Query.Order ( orderBy )
5556import Rel8.Query.These ( alignBy )
5657import Rel8.Table ( Table )
57−import Rel8.Table.Aggregate ( groupBy, headAgg, listAgg, nonEmptyAgg )
58+import Rel8.Table.Aggregate ( groupBy, listAgg, nonEmptyAgg )
5859import Rel8.Table.Alternative
5960 ( AltTable, (<|>:)
6061 , AlternativeTable, emptyTable
@@ -63,6 +64,8 @@ import Rel8.Table.Eq ( EqTable, (==:) )
6364import Rel8.Table.List ( ListTable )
6465import Rel8.Table.Maybe ( MaybeTable, maybeTable )
6566import Rel8.Table.NonEmpty ( NonEmptyTable )
67+import Rel8.Table.Ord ( OrdTable )
68+import Rel8.Table.Order ( ascTable )
6669import Rel8.Table.These ( TheseTable, theseTable )
6770
6871-- semigroupoids
@@ -337,26 +340,26 @@ difference kas kbs = do
337340
338341aggregateTabulation :: EqTable k
339342 => Tabulation k (Aggregate a) -> Tabulation k a
340−aggregateTabulation kas = do
341− as <- toQuery kas
342− fromQuery $ aggregate $ bitraverse1 groupBy id <$> as
343+aggregateTabulation = mapQuery (aggregate . fmap (bitraverse1 groupBy id))
343344
344345
345−-- | 'orderTabulation' orders the /values/ of a 'Tabulation' (not the keys).
346+-- | 'orderTabulation' orders the /values/ of a 'Tabulation' within each key.
347+--
346348-- In general this is meaningless, but if used together with 'manyTabulation'
347349-- or 'someTabulation', the resulting lists will be ordered according to
348350-- ordering given to 'orderTabulation'.
349−orderTabulation :: Order a -> Tabulation k a -> Tabulation k a
350−orderTabulation ordering (Tabulation as) =
351− Tabulation $ orderBy (snd >$< ordering) . as
351+orderTabulation :: OrdTable k => Order a -> Tabulation k a -> Tabulation k a
352+orderTabulation ordering = mapQuery $ orderBy ordering'
353+ where
354+ ordering' = (fst >$< ascTable) <> (snd >$< ordering)
352355
353356
354357-- | Turns the given 'Tabulation' from a \"multimap\" into a \"map\". If there
355358-- is more than one value at a particular key, only the first one is kept.
356359-- \"First\" is in general undefined, but 'orderTabulation' can be used to
357360-- make it deterministic.
358−singularize :: (EqTable k, Table Expr a) => Tabulation k a -> Tabulation k a
359−singularize = aggregateTabulation . fmap headAgg
361+distinctTabulation :: EqTable k => Tabulation k a -> Tabulation k a
362+distinctTabulation = mapQuery (distinctOn fst)
360363
361364
362365optionalTabulation :: EqTable k
@@ -380,6 +383,11 @@ someTabulation :: (EqTable k, Table Expr a)
380383someTabulation = aggregateTabulation . fmap nonEmptyAgg
381384
382385
386+mapQuery :: (Query (k, a) -> Query (k, b)) -> Tabulation k a -> Tabulation k b
387+mapQuery f (Tabulation query) = Tabulation $ \k ->
388+ first Just <$> f (first (fromMaybe k) <$> query k)
389+
390+
383391toQuery :: Tabulation k a -> Tabulation k (Query (k, a))
384392toQuery (Tabulation as) = Tabulation $ \k ->
385393 pure (Nothing, first (fromMaybe k) <$> as k)