packages feed

hypertypes-0.2.2: src/Hyper/Type/Functor.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Lift Functors to HyperTypes
module Hyper.Type.Functor
    ( F (..)
    , _F
    , W_F (..)
    ) where

import Control.Lens (iso, mapped)
import Hyper
import Hyper.Class.Monad (HMonad (..))

import Hyper.Internal.Prelude

-- | Lift a 'Functor', or type constructor of kind @Type -> Type@ to a 'Hyper.Type.HyperType'.
--
-- * @F Maybe@ can be used to encode structures with missing values
-- * @F (Either Text)@ can be used to encode results of parsing where structure components
--   may fail to parse.
newtype F f h = F (f (h :# F f))
    deriving stock (Generic)

-- | An 'Iso' from 'F' to its content.
--
-- Using `_F` rather than the 'F' data constructor is recommended,
-- because it helps the type inference know that @F f@ is parameterized with a 'Hyper.Type.HyperType'.
_F ::
    Iso
        (F f0 # k0)
        (F f1 # k1)
        (f0 (k0 # F f0))
        (f1 (k1 # F f1))
_F = iso (\(F x) -> x) F

makeCommonInstances [''F]
makeHTraversableApplyAndBases ''F

instance Monad f => HMonad (F f) where
    hjoin =
        ( _F
            %~ ( >>=
                    ( mapped %~ t . (^. _HCompose)
                    )
                        . (^. _HCompose . _F)
               )
        )
            . (^. _HCompose)
        where
            t ::
                forall p.
                Recursively HFunctor p =>
                p # HCompose (F f) (F f) ->
                p # F f
            t =
                hmap (Proxy @(Recursively HFunctor) #> hjoin)
                    \\ recursively (Proxy @(HFunctor p))

instance RNodes (F f)
instance c (F f) => Recursively c (F f)
instance Traversable f => RTraversable (F f)