linear-generics-0.1.0.0: tests/Generics/Deriving/TraversableConf.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# language RankNTypes #-}
-- | A \"confusing\" default implementation of a 'Traversable'-like class that
-- produces code very much like derived instances. It uses the same magic
-- behind @Control.Lens.Traversal.confusing@.
module Generics.Deriving.TraversableConf (
-- * Generic Traversable class
GTraversable(..)
-- * Default method
, gtraversedefault
-- * Internal Traversable class
, GTraversable'(..)
) where
import Control.Applicative (Const, WrappedMonad(..), ZipList)
import qualified Data.Monoid as Monoid (First, Last, Product, Sum)
import Data.Monoid (Dual)
import Generics.Linear
import Generics.Deriving.Foldable
import Generics.Deriving.Functor
import Data.Complex (Complex)
import Data.Ord (Down)
import Data.Proxy (Proxy)
import Data.Functor.Identity (Identity)
import qualified Data.Functor.Product as Functor (Product)
import qualified Data.Functor.Sum as Functor (Sum)
import Data.Functor.Compose (Compose)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.Semigroup as Semigroup (First, Last)
import Data.Semigroup (Arg, Max, Min, WrappedMonoid)
--------------------------------------------------------------------------------
-- Generic traverse
--------------------------------------------------------------------------------
class GTraversable' t where
gtraverse' :: Applicative f => (a -> f b) -> t a -> CY f (t b)
instance GTraversable' V1 where
gtraverse' _ x = pure $ case x of
instance GTraversable' U1 where
gtraverse' _ U1 = pure U1
instance GTraversable' Par1 where
gtraverse' f (Par1 a) = Par1 <$> liftCY (f a)
instance GTraversable' (K1 i c) where
gtraverse' _ (K1 a) = pure (K1 a)
instance GTraversable' f => GTraversable' (M1 i c f) where
gtraverse' f (M1 a) = M1 <$> gtraverse' f a
instance GTraversable' f => GTraversable' (MP1 m f) where
gtraverse' f (MP1 a) = (\x -> MP1 x) <$> gtraverse' f a
instance (GTraversable' f, GTraversable' g) => GTraversable' (f :+: g) where
gtraverse' f (L1 a) = L1 <$> gtraverse' f a
gtraverse' f (R1 a) = R1 <$> gtraverse' f a
instance (GTraversable' f, GTraversable' g) => GTraversable' (f :*: g) where
gtraverse' f (a :*: b) = (:*:) <$> gtraverse' f a <*> gtraverse' f b
instance (GTraversable' f, GTraversable g) => GTraversable' (f :.: g) where
gtraverse' f (Comp1 x) = Comp1 <$> gtraverse' (gtraverse f) x
instance GTraversable' UAddr where
gtraverse' _ (UAddr a) = pure (UAddr a)
instance GTraversable' UChar where
gtraverse' _ (UChar c) = pure (UChar c)
instance GTraversable' UDouble where
gtraverse' _ (UDouble d) = pure (UDouble d)
instance GTraversable' UFloat where
gtraverse' _ (UFloat f) = pure (UFloat f)
instance GTraversable' UInt where
gtraverse' _ (UInt i) = pure (UInt i)
instance GTraversable' UWord where
gtraverse' _ (UWord w) = pure (UWord w)
class (GFunctor t, GFoldable t) => GTraversable t where
gtraverse :: Applicative f => (a -> f b) -> t a -> f (t b)
default gtraverse :: (Generic1 t, GTraversable' (Rep1 t), Applicative f)
=> (a -> f b) -> t a -> f (t b)
gtraverse = gtraversedefault
gsequenceA :: Applicative f => t (f a) -> f (t a)
gsequenceA = gtraverse id
gmapM :: Monad m => (a -> m b) -> t a -> m (t b)
gmapM f = unwrapMonad . gtraverse (WrapMonad . f)
gsequence :: Monad m => t (m a) -> m (t a)
gsequence = gmapM id
gtraversedefault :: (Generic1 t, GTraversable' (Rep1 t), Applicative f)
=> (a -> f b) -> t a -> f (t b)
gtraversedefault f x = lowerCY $ to1 <$> gtraverse' f (from1 x)
{-# INLINE gtraversedefault #-}
-- Base types instances
instance GTraversable ((,) a)
instance GTraversable ((,,) a b)
instance GTraversable ((,,,) a b c)
instance GTraversable []
instance GTraversable (Arg a)
instance GTraversable Complex
instance GTraversable (Const m)
instance GTraversable Down
instance GTraversable Dual
instance GTraversable (Either a)
instance GTraversable Monoid.First
instance GTraversable (Semigroup.First)
instance GTraversable Identity
instance GTraversable Monoid.Last
instance GTraversable Semigroup.Last
instance GTraversable Max
instance GTraversable Maybe
instance GTraversable Min
instance GTraversable NonEmpty
instance GTraversable Monoid.Product
instance (GTraversable f, GTraversable g) => GTraversable (Functor.Product f g)
instance (GTraversable f, GTraversable g) => GTraversable (Compose f g)
instance GTraversable Proxy
instance GTraversable Monoid.Sum
instance (GTraversable f, GTraversable g) => GTraversable (Functor.Sum f g)
instance GTraversable WrappedMonoid
instance GTraversable ZipList
-- The types below are stolen from kan-extensions, and used in the same way as
-- Control.Lens.Traversal.confusing. Note that this is *not* equivalent to
-- applying `confusing` itself to a plain traversal: the latter seems to make a
-- mess with types like
--
-- data Gramp f a = Gramp Int a (f a)
newtype Curried g h a = Curried (forall r. g (a -> r) -> h r)
instance Functor g => Functor (Curried g h) where
fmap f (Curried g) = Curried (g . fmap (.f))
{-# INLINE fmap #-}
instance (Functor g, g ~ h) => Applicative (Curried g h) where
pure a = Curried (fmap ($ a))
{-# INLINE pure #-}
Curried mf <*> Curried ma = Curried (ma . mf . fmap (.))
{-# INLINE (<*>) #-}
lowerCurried :: Applicative f => Curried f g a -> g a
lowerCurried (Curried f) = f (pure id)
{-# INLINE lowerCurried #-}
newtype Yoneda f a = Yoneda { runYoneda :: forall b. (a -> b) -> f b }
lowerYoneda :: Yoneda f a -> f a
lowerYoneda (Yoneda f) = f id
{-# INLINE lowerYoneda #-}
instance Functor (Yoneda f) where
fmap f m = Yoneda (\k -> runYoneda m (k . f))
{-# INLINE fmap #-}
instance Applicative f => Applicative (Yoneda f) where
pure a = Yoneda (\f -> pure (f a))
{-# INLINE pure #-}
Yoneda m <*> Yoneda n = Yoneda (\f -> m (f .) <*> n id)
{-# INLINE (<*>) #-}
-- Lifted from the implementation of Control.Lens.Traversal.confusing
liftCurriedYoneda :: Applicative f => f a -> Curried (Yoneda f) (Yoneda f) a
liftCurriedYoneda fa = Curried (`yap` fa)
{-# INLINE liftCurriedYoneda #-}
yap :: Applicative f => Yoneda f (a -> b) -> f a -> Yoneda f b
yap (Yoneda k) fa = Yoneda (\ab_r -> k (ab_r .) <*> fa)
{-# INLINE yap #-}
-- This wrapper makes it easy to swap out implementations.
-- See, for example, https://github.com/glguy/generic-traverse,
-- which is essentially the same but uses a custom @Boggle@
-- type. I don't have a good sense of the tradeoffs between
-- the two.
newtype CY f a = CY { unCY :: Curried (Yoneda f) (Yoneda f) a }
deriving newtype (Functor, Applicative)
liftCY :: Applicative f => f a -> CY f a
liftCY = CY . liftCurriedYoneda
lowerCY :: Applicative f => CY f a -> f a
lowerCY = lowerYoneda . lowerCurried . unCY