vessel-0.1.0.0: src/Data/Vessel/ViewMorphism.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Vessel.ViewMorphism where
------- Selectable convenience class -------
import Prelude hiding (id, (.))
import Control.Monad
import Control.Applicative
import Control.Category
import Data.Bifunctor
import Data.Functor.Identity
import Data.These
import Reflex.Query.Class
import Reflex.Class
import Data.Align
import Data.Vessel.Internal ()
type family ViewQueryResult (v :: k) :: k
type instance ViewQueryResult (Const g x) = Identity x
type instance ViewQueryResult (Const g) = Identity
type instance ViewQueryResult (a, b) = These (ViewQueryResult a) (ViewQueryResult b)
-- a way to request partially loaded information;
data ViewHalfMorphism m n p q = ViewHalfMorphism
{ _viewMorphism_mapQuery :: p -> m q
, _viewMorphism_mapQueryResult :: ViewQueryResult q -> n (ViewQueryResult p) -- TODO Loading data
}
data ViewMorphism m n p q = ViewMorphism
{ _viewMorphism_to :: ViewHalfMorphism m n p q
, _viewMorphism_from :: ViewHalfMorphism n m q p
}
type ViewMorphismSimple = ViewMorphism Identity Maybe
instance (Monad m, Monad n) => Category (ViewHalfMorphism n m) where
id = ViewHalfMorphism pure pure
ViewHalfMorphism f f' . ViewHalfMorphism g g' = ViewHalfMorphism (f <=< g) (f' >=> g')
instance (Monad m, Monad n) => Category (ViewMorphism m n) where
id = ViewMorphism id id
ViewMorphism f f' . ViewMorphism g g' = ViewMorphism (f . g) (g' . f')
instance (Semigroup (m b) , Semigroup (n (ViewQueryResult a))) => Semigroup (ViewHalfMorphism m n a b) where
ViewHalfMorphism f f' <> ViewHalfMorphism g g' = ViewHalfMorphism (f <> g) (f' <> g')
instance (Monoid (m b) , Monoid (n (ViewQueryResult a))) => Monoid (ViewHalfMorphism m n a b) where
mappend = (<>)
mempty = ViewHalfMorphism mempty mempty
instance
( Semigroup (m b), Semigroup (m (ViewQueryResult b))
, Semigroup (n a), Semigroup (n (ViewQueryResult a))
) => Semigroup (ViewMorphism m n a b) where
ViewMorphism f f' <> ViewMorphism g g' = ViewMorphism (f <> g) (f' <> g')
instance
( Monoid (m b), Monoid (m (ViewQueryResult b))
, Monoid (n a), Monoid (n (ViewQueryResult a))
) => Monoid (ViewMorphism m n a b) where
mappend = (<>)
mempty = ViewMorphism mempty mempty
-- | query for two things simultaneously, return as much result as is available.
zipViewMorphism
::
( Semigroup (m c)
, Semigroup (m (ViewQueryResult c))
, Semialign n
, Applicative n
)
=> ViewMorphism m n a c -> ViewMorphism m n b c -> ViewMorphism m n (a, b) c
zipViewMorphism (ViewMorphism f f') (ViewMorphism g g') = ViewMorphism (toZipViewMorphism f g) (fromZipViewMorphism f' g')
toZipViewMorphism :: forall m n a b c. (Semialign n, Semigroup (m c)) => ViewHalfMorphism m n a c -> ViewHalfMorphism m n b c -> ViewHalfMorphism m n (a, b) c
toZipViewMorphism (ViewHalfMorphism a2c c2a' ) (ViewHalfMorphism b2c c2b' ) = ViewHalfMorphism
{ _viewMorphism_mapQuery = \(x, y) -> a2c x <> b2c y
, _viewMorphism_mapQueryResult = \r -> align (c2a' r) (c2b' r)
}
fromZipViewMorphism
:: forall m n a b c.
( Applicative m
, Semigroup (n (ViewQueryResult c))
) => ViewHalfMorphism m n c a -> ViewHalfMorphism m n c b -> ViewHalfMorphism m n c (a, b)
fromZipViewMorphism (ViewHalfMorphism c2a a2c') (ViewHalfMorphism c2b b2c') = ViewHalfMorphism
{ _viewMorphism_mapQuery = \r -> liftA2 (,) (c2a r) (c2b r)
, _viewMorphism_mapQueryResult = these id id ((<>)) . bimap a2c' b2c'
}
queryViewMorphism :: forall t (p :: *) (q :: *) m partial.
( Reflex t
, MonadQuery t q m
, Monad m
, QueryResult q ~ ViewQueryResult q
)
=> p -> Dynamic t (ViewMorphism Identity partial p q) -> m (Dynamic t (partial (ViewQueryResult p)))
queryViewMorphism x q = do
v :: Dynamic t (QueryResult q) <- queryDyn $ (\(ViewMorphism (ViewHalfMorphism f _) _) -> runIdentity $ f x) <$> q
return $ (\v' (ViewMorphism (ViewHalfMorphism _ g) _) -> g v') <$> v <*> q