2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FunctionalDependencies #-}
6{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE UndecidableInstances #-}
13-- A class that ties together queries to some data source and their results,
14-- providing methods for requesting data from the source and accumulating
16module Reflex.Query.Class
20 , combineSelectedCounts
30import Control.Category (Category)
31import qualified Control.Category as Cat
32import Control.Monad.Reader
36import Data.Map.Monoidal (MonoidalMap)
37import qualified Data.Map.Monoidal as MonoidalMap
38import Data.Semigroup (Semigroup(..))
39import Foreign.Storable
41import Data.Monoid hiding ((<>))
42import Control.Applicative
46-- | A 'Query' can be thought of as a declaration of interest in some set of data.
47-- A 'QueryResult' is the set of data associated with that interest set.
48-- The @crop@ function provides a way to determine what part of a given 'QueryResult'
49-- is relevant to a given 'Query'.
50class (Monoid (QueryResult a), Semigroup (QueryResult a)) => Query a where
51 type QueryResult a :: *
52 crop :: a -> QueryResult a -> QueryResult a
54instance (Ord k, Query v) => Query (MonoidalMap k v) where
55 type QueryResult (MonoidalMap k v) = MonoidalMap k (QueryResult v)
56 crop q r = MonoidalMap.intersectionWith (flip crop) r q
58-- | the result of two queries is both results.
59instance (Query a, Query b) => Query (a, b) where
60 type QueryResult (a, b) = (QueryResult a, QueryResult b)
61 crop (x, x') (y, y') = (crop x y, crop x' y')
63-- | Trivial queries have trivial results.
64instance Query () where
65 type QueryResult () = ()
68-- | The result of an absurd query is trivial; If you can ask the question, the
69-- answer cannot tell you anything you didn't already know.
71-- 'QueryResult Void = @Void@' seems like it would also work, but that has
72-- problems of robustness. In some applications, an unasked question can still
73-- be answered, so it is important that the result is inhabited even when the
74-- question isn't. Applications that wish to prevent this can mandate that the
75-- query result be paired with the query: then the whole response will be
76-- uninhabited as desired.
77instance Query Void where
78 type QueryResult Void = ()
81#if MIN_VERSION_base(4,12,0)
82-- | We can lift queries into monoidal containers.
83-- But beware of Applicatives whose monoid is different from (pure mempty, liftA2 mappend)
84instance (Query q, Applicative f) => Query (Ap f q) where
85 type QueryResult (Ap f q) = Ap f (QueryResult q)
89-- | QueryMorphism's must be group homomorphisms when acting on the query type
90-- and compatible with the query relationship when acting on the query result.
91data QueryMorphism q q' = QueryMorphism
92 { _queryMorphism_mapQuery :: q -> q'
93 , _queryMorphism_mapQueryResult :: QueryResult q' -> QueryResult q
96instance Category QueryMorphism where
97 id = QueryMorphism id id
98 qm . qm' = QueryMorphism
99 { _queryMorphism_mapQuery = mapQuery qm . mapQuery qm'
100 , _queryMorphism_mapQueryResult = mapQueryResult qm' . mapQueryResult qm
103-- | Apply a 'QueryMorphism' to a 'Query'
104mapQuery :: QueryMorphism q q' -> q -> q'
105mapQuery = _queryMorphism_mapQuery
107-- | Map a 'QueryMorphism' to a 'QueryResult'
108mapQueryResult :: QueryMorphism q q' -> QueryResult q' -> QueryResult q
109mapQueryResult = _queryMorphism_mapQueryResult
111-- | This type can be used to track of the frequency of interest in a given 'Query'. See note on
112-- 'combineSelectedCounts'
113newtype SelectedCount = SelectedCount { unSelectedCount :: Int }
114 deriving (Eq, Ord, Show, Read, Integral, Num, Bounded, Enum, Real, Ix, Bits, FiniteBits, Storable, Data)
116instance Semigroup SelectedCount where
117 SelectedCount a <> SelectedCount b = SelectedCount (a + b)
119instance Monoid SelectedCount where
120 mempty = SelectedCount 0
123instance Group SelectedCount where
124 negateG (SelectedCount a) = SelectedCount (negate a)
126instance Additive SelectedCount
128-- | The Semigroup\/Monoid\/Group instances for a Query containing 'SelectedCount's should use
129-- this function which returns Nothing if the result is 0. This allows the pruning of leaves
130-- of the 'Query' that are no longer wanted.
131combineSelectedCounts :: SelectedCount -> SelectedCount -> Maybe SelectedCount
132combineSelectedCounts (SelectedCount i) (SelectedCount j) = if i == negate j then Nothing else Just $ SelectedCount (i + j)
134-- | A class that allows sending of 'Query's and retrieval of 'QueryResult's. See 'queryDyn' for a commonly
136class (Group q, Additive q, Query q, Monad m) => MonadQuery t q m | m -> q t where
137 tellQueryIncremental :: Incremental t (AdditivePatch q) -> m ()
138 askQueryResult :: m (Dynamic t (QueryResult q))
139 queryIncremental :: Incremental t (AdditivePatch q) -> m (Dynamic t (QueryResult q))
141instance MonadQuery t q m => MonadQuery t q (ReaderT r m) where
142 tellQueryIncremental = lift . tellQueryIncremental
143 askQueryResult = lift askQueryResult
144 queryIncremental = lift . queryIncremental
146-- | Produce and send an 'Incremental' 'Query' from a 'Dynamic' 'Query'.
147tellQueryDyn :: (Reflex t, MonadQuery t q m) => Dynamic t q -> m ()
148tellQueryDyn d = tellQueryIncremental $ unsafeBuildIncremental (sample (current d)) $ attachWith (\old new -> AdditivePatch $ new ~~ old) (current d) (updated d)
150-- | Retrieve 'Dynamic'ally updating 'QueryResult's for a 'Dynamic'ally updating 'Query'.
151queryDyn :: (Reflex t, MonadQuery t q m) => Dynamic t q -> m (Dynamic t (QueryResult q))
154 zipDynWith crop q <$> askQueryResult
156-- | Use a query morphism to operate on a smaller version of a query.
157subQuery :: (Reflex t, MonadQuery t q2 m) => QueryMorphism q1 q2 -> Dynamic t q1 -> m (Dynamic t (QueryResult q1))
158subQuery (QueryMorphism f g) x = fmap g <$> queryDyn (fmap f x)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list