packages feed

backprop-0.2.7.0: src/Data/Type/Util.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Data.Type.Util (
  runzipWith,
  rzipWithM_,
  Replicate,
  VecT (.., (:+)),
  vmap,
  withVec,
  vecToRec,
  fillRec,
  zipVecList,
  splitRec,
  p1,
  p2,
  s1,
  s2,
) where

import Data.Bifunctor
import Data.Functor.Identity
import Data.Kind
import Data.Proxy
import Data.Vinyl.Core
import Data.Vinyl.TypeLevel
import GHC.Generics
import Lens.Micro

runzipWith ::
  forall f g h.
  () =>
  (forall x. f x -> (g x, h x)) ->
  (forall xs. Rec f xs -> (Rec g xs, Rec h xs))
runzipWith f = go
  where
    go :: forall ys. Rec f ys -> (Rec g ys, Rec h ys)
    go = \case
      RNil -> (RNil, RNil)
      x :& xs ->
        let (y, z) = f x
            (ys, zs) = go xs
         in (y :& ys, z :& zs)
{-# INLINE runzipWith #-}

data VecT :: Nat -> (k -> Type) -> k -> Type where
  VNil :: VecT 'Z f a
  (:*) :: !(f a) -> VecT n f a -> VecT ('S n) f a

pattern (:+) :: a -> VecT n Identity a -> VecT ('S n) Identity a
pattern x :+ xs = Identity x :* xs

vmap ::
  forall n f g a.
  () =>
  (f a -> g a) -> VecT n f a -> VecT n g a
vmap f = go
  where
    go :: VecT m f a -> VecT m g a
    go = \case
      VNil -> VNil
      x :* xs -> f x :* go xs
{-# INLINE vmap #-}

withVec ::
  [f a] ->
  (forall n. VecT n f a -> r) ->
  r
withVec = \case
  [] -> \f -> f VNil
  x : xs -> \f -> withVec xs (f . (x :*))
{-# INLINE withVec #-}

type family Replicate (n :: Nat) (a :: k) = (as :: [k]) | as -> n where
  Replicate 'Z a = '[]
  Replicate ('S n) a = a ': Replicate n a

vecToRec ::
  VecT n f a ->
  Rec f (Replicate n a)
vecToRec = \case
  VNil -> RNil
  x :* xs -> x :& vecToRec xs
{-# INLINE vecToRec #-}

fillRec ::
  forall f g as c.
  () =>
  (forall a. f a -> c -> g a) ->
  Rec f as ->
  [c] ->
  Maybe (Rec g as)
fillRec f = go
  where
    go :: Rec f bs -> [c] -> Maybe (Rec g bs)
    go = \case
      RNil -> \_ -> Just RNil
      x :& xs -> \case
        [] -> Nothing
        y : ys -> (f x y :&) <$> go xs ys
{-# INLINE fillRec #-}

rzipWithM_ ::
  forall h f g as.
  Applicative h =>
  (forall a. f a -> g a -> h ()) ->
  Rec f as ->
  Rec g as ->
  h ()
rzipWithM_ f = go
  where
    go :: forall bs. Rec f bs -> Rec g bs -> h ()
    go = \case
      RNil -> \case
        RNil -> pure ()
      x :& xs -> \case
        y :& ys -> f x y *> go xs ys
{-# INLINE rzipWithM_ #-}

zipVecList ::
  forall a b c f g n.
  () =>
  (f a -> Maybe b -> g c) ->
  VecT n f a ->
  [b] ->
  VecT n g c
zipVecList f = go
  where
    go :: VecT m f a -> [b] -> VecT m g c
    go = \case
      VNil -> const VNil
      x :* xs -> \case
        [] -> f x Nothing :* go xs []
        y : ys -> f x (Just y) :* go xs ys
{-# INLINE zipVecList #-}

splitRec ::
  forall f as bs.
  RecApplicative as =>
  Rec f (as ++ bs) ->
  (Rec f as, Rec f bs)
splitRec = go (rpure Proxy)
  where
    go :: Rec Proxy as' -> Rec f (as' ++ bs) -> (Rec f as', Rec f bs)
    go = \case
      RNil -> (RNil,)
      _ :& ps -> \case
        x :& xs -> first (x :&) $ go ps xs
{-# INLINE splitRec #-}

p1 :: Lens' ((f :*: g) a) (f a)
p1 f (x :*: y) = (:*: y) <$> f x
{-# INLINE p1 #-}

p2 :: Lens' ((f :*: g) a) (g a)
p2 f (x :*: y) = (x :*:) <$> f y
{-# INLINE p2 #-}

s1 :: Traversal' ((f :+: g) a) (f a)
s1 f (L1 x) = L1 <$> f x
s1 _ (R1 y) = pure (R1 y)
{-# INLINE s1 #-}

s2 :: Traversal' ((f :+: g) a) (g a)
s2 _ (L1 x) = pure (L1 x)
s2 f (R1 y) = R1 <$> f y
{-# INLINE s2 #-}