packages feed

pure-borrow-0.0.0.0: src/Control/Monad/Borrow/Pure/Experimental/Loop.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeAbstractions #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

{- |
This module provides 'Foldable' class, and provides a way to loop through it while reborrowing existing 'Borrow's into sublifetime.
The module also introduces 'Borrows', which is a heterogeneous list of 'Borrow's in the same lifetime.
-}
module Control.Monad.Borrow.Pure.Experimental.Loop (
  Borrows (..),
  forReborrowing,
  forReborrowingOf_,
  forReborrowing_,
  iforReborrowingOf_,
  iforReborrowing_,
  Fold,
  Foldable (..),
  IndexedFold,
  ifoldMapDefaultOf,
  FoldableWithIndex (..),
  traverse_,
  for_,
  toListOf,
  toList,
  foldBorrow,
  foldBorrowOf,
  GenericFoldable,
  genericFoldMap,
  ifoldMapDefault,
) where

import Control.Functor.Linear qualified as Control
import Control.Monad.Borrow.Pure
import Control.Monad.Borrow.Pure.BO.Unsafe
import Control.Monad.Borrow.Pure.Experimental.Borrows
import Control.Monad.Borrow.Pure.Experimental.Reborrowable
import Control.Monad.Borrow.Pure.Utils (coerceLin)
import Data.Bifunctor.Linear qualified as Bi
import Data.Functor.Linear qualified as Data
import Data.HashMap.Mutable.Linear qualified as LHM
import Data.List.NonEmpty.Linear (NonEmpty)
import Data.List.NonEmpty.Linear qualified as LNE
import Data.Monoid.Linear
import Data.Vector.Mutable.Linear qualified as LV
import Generics.Linear
import Prelude.Linear hiding (foldMap)
import Prelude.Linear qualified as PL
import Unsafe.Linear qualified as Unsafe

{- |
@'forReborrowingN' iterates over the elements of 'Data.Traversable' @t@
inside the delimited sublifetime, reborrowing the 'Borrows' in @bors@ for that sublifetime.
-}
forReborrowing ::
  (Data.Traversable t, Reborrowable bor) =>
  bor α xs %1 ->
  t b %1 ->
  ( forall β.
    bor (β /\ α) xs %1 ->
    b %1 ->
    BO (β /\ α) c
  ) ->
  BO α (t c, bor α xs)
{-# INLINE forReborrowing #-}
forReborrowing bors tb k =
  flip Control.runStateT bors $
    Data.for tb \a -> Control.StateT \bors ->
      locally bors (\bors -> k bors a)

type Fold s a = forall w. (Monoid w) => (a %1 -> w) -> s %1 -> w

-- See https://github.com/tweag/linear-base/issues/190 for the discussion.
class Foldable t where
  foldMap :: (Monoid w) => (a %1 -> w) -> t a %1 -> w

type IndexedFold i s a = forall w. (Monoid w) => (i %1 -> a %1 -> w) -> s %1 -> w

class (Foldable t) => FoldableWithIndex i t | t -> i where
  ifoldMap :: (Monoid w) => (i %1 -> a %1 -> w) -> t a %1 -> w
  default ifoldMap ::
    (Foldable t, i ~ Int, Monoid w) =>
    (i %1 -> a %1 -> w) -> t a %1 -> w
  ifoldMap = ifoldMapDefault
  {-# INLINE ifoldMap #-}

ifoldMapDefaultOf :: forall s a. Fold s a %1 -> IndexedFold Int s a
{-# INLINE ifoldMapDefaultOf #-}
ifoldMapDefaultOf fld k s =
  flip Control.evalState (Ur 0) $ unAp $ flip fld s $ \a -> Ap Control.do
    Ur i <- Control.get
    Control.put $ Ur $! i + 1
    Control.pure $ k i a

ifoldMapDefault :: (Foldable t) => IndexedFold Int (t a) a
{-# INLINE ifoldMapDefault #-}
ifoldMapDefault = ifoldMapDefaultOf foldMap

foldBorrowOf :: Fold s a %1 -> Fold (Borrow bk α s) (Borrow bk α a)
{-# INLINE foldBorrowOf #-}
foldBorrowOf fld k = fld (k . UnsafeAlias) . unsafeUnalias

foldBorrow :: (Foldable t) => Fold (Borrow bk α (t a)) (Borrow bk α a)
{-# INLINE foldBorrow #-}
foldBorrow = foldBorrowOf foldMap

traverse_ :: (Foldable t, Data.Applicative m) => (a %1 -> m ()) -> t a %1 -> m ()
{-# INLINE traverse_ #-}
traverse_ f = unAp . foldMap (Ap . f)

for_ :: (Foldable t, Data.Applicative m) => t a %1 -> (a %1 -> m ()) -> m ()
{-# INLINE for_ #-}
for_ = flip traverse_

newtype Ap m a = Ap (m a)
  deriving newtype (Data.Functor, Control.Functor, Data.Applicative, Control.Applicative)

instance (Data.Applicative f, Semigroup w) => Semigroup (Ap f w) where
  (<>) = Data.liftA2 (<>)
  {-# INLINE (<>) #-}

instance (Data.Applicative f, Monoid w) => Monoid (Ap f w) where
  mempty = Data.pure mempty
  {-# INLINE mempty #-}

unAp :: Ap m a %1 -> m a
unAp (Ap m) = m
{-# INLINE unAp #-}

forReborrowingOf_ ::
  (Reborrowable bor) =>
  Fold s a %1 ->
  bor α xs %1 ->
  s %1 ->
  ( forall β.
    bor (β /\ α) xs %1 ->
    a %1 ->
    BO (β /\ α) ()
  ) ->
  BO α (bor α xs)
{-# INLINE forReborrowingOf_ #-}
forReborrowingOf_ fld bors s k =
  flip Control.execStateT bors $
    unAp $
      flip fld s $
        Ap . \a -> Control.StateT \bors -> locally bors (\bors -> k bors a)

forReborrowing_ ::
  (Foldable t, Reborrowable bor) =>
  bor α xs %1 ->
  t a %1 ->
  ( forall β.
    bor (β /\ α) xs %1 ->
    a %1 ->
    BO (β /\ α) ()
  ) ->
  BO α (bor α xs)
{-# INLINE forReborrowing_ #-}
forReborrowing_ = forReborrowingOf_ foldMap

iforReborrowingOf_ ::
  (Reborrowable bor) =>
  IndexedFold i s a %1 ->
  bor α xs %1 ->
  s %1 ->
  ( forall β.
    bor (β /\ α) xs %1 ->
    i %1 ->
    a %1 ->
    BO (β /\ α) ()
  ) ->
  BO α (bor α xs)
{-# INLINE iforReborrowingOf_ #-}
iforReborrowingOf_ fld bors s k =
  flip Control.execStateT bors $
    unAp $
      flip fld s \i a ->
        Ap $ Control.StateT \bors -> locally bors (\bors -> k bors i a)

iforReborrowing_ ::
  (FoldableWithIndex i t, Reborrowable bor) =>
  bor α xs %1 ->
  t a %1 ->
  ( forall β.
    bor (β /\ α) xs %1 ->
    i %1 ->
    a %1 ->
    BO (β /\ α) ()
  ) ->
  BO α (bor α xs)
{-# INLINE iforReborrowing_ #-}
iforReborrowing_ = iforReborrowingOf_ ifoldMap

toListOf :: Fold s a %1 -> s %1 -> [a]
{-# INLINE toListOf #-}
toListOf fld = fromDList . fld singletonDL

toList :: (Foldable t) => t a %1 -> [a]
{-# INLINE toList #-}
toList = toListOf foldMap

newtype DList a = DList ([a] %1 -> [a])

fromDList :: DList a %1 -> [a]
{-# INLINE fromDList #-}
fromDList (DList f) = f []

singletonDL :: a %1 -> DList a
{-# INLINE singletonDL #-}
singletonDL a = DList (a :)

instance Semigroup (DList a) where
  DList f <> DList g = DList (f . g)
  {-# INLINE (<>) #-}

instance Monoid (DList a) where
  mempty = DList id
  {-# INLINE mempty #-}

instance Foldable [] where
  foldMap = PL.foldMap
  {-# INLINE foldMap #-}

deriving anyclass instance FoldableWithIndex Int []

instance Foldable Maybe where
  foldMap f = maybe mempty f
  {-# INLINE foldMap #-}

instance FoldableWithIndex () Maybe where
  ifoldMap f = foldMap (f ())
  {-# INLINE ifoldMap #-}

instance (Consumable e) => Foldable ((,) e) where
  foldMap f = uncurry lseq . Bi.bimap consume f
  {-# INLINE foldMap #-}

instance (Consumable e) => Foldable (Either e) where
  foldMap f = either ((`lseq` mempty) . consume) f
  {-# INLINE foldMap #-}

instance Foldable NonEmpty where
  foldMap f = foldMap f . LNE.toList
  {-# INLINE foldMap #-}

instance Foldable U1 where
  foldMap _f = \U1 -> mempty
  {-# INLINE foldMap #-}

instance Foldable V1 where
  foldMap _ = \case {}
  {-# INLINE foldMap #-}

instance (Foldable f) => Foldable (M1 i c f) where
  foldMap f = coerceLin $ foldMap @f f
  {-# INLINE foldMap #-}

instance (Foldable f) => Foldable (MP1 m f) where
  foldMap f (MP1 x) = foldMap f x
  {-# INLINE foldMap #-}

instance (Foldable f, Foldable g) => Foldable (f :*: g) where
  foldMap f (x :*: y) = foldMap f x <> foldMap f y

instance (Foldable f, Foldable g) => Foldable (f :+: g) where
  foldMap f = \case
    L1 x -> foldMap f x
    R1 y -> foldMap f y
  {-# INLINE foldMap #-}

type GenericFoldable t = (Generic1 t, Foldable (Rep1 t))

genericFoldMap :: (GenericFoldable t, Monoid w) => (a %1 -> w) -> t a %1 -> w
{-# INLINE genericFoldMap #-}
genericFoldMap f = foldMap f . from1

instance (GenericFoldable t) => Foldable (Generically1 t) where
  foldMap f = genericFoldMap f . (\(Generically1 x) -> x)
  {-# INLINE foldMap #-}

instance Foldable LV.Vector where
  foldMap f vec =
    LV.size vec & \case
      (Ur n, vec) -> DataFlow.do
        let {-# INLINE loop #-}
            loop !vec !i !w
              | i < n =
                  LV.unsafeGet i vec & \(Ur a, vec) -> DataFlow.do
                    let !w' = w <> f a
                    loop vec (i + 1) w'
              | otherwise = vec `lseq` w
        loop vec 0 mempty
  {-# INLINE foldMap #-}

deriving anyclass instance FoldableWithIndex Int LV.Vector

instance Foldable (LHM.HashMap k) where
  foldMap f hm = foldMap (Unsafe.toLinear \(_, v) -> f v) $ unur $ LHM.toList hm

instance FoldableWithIndex k (LHM.HashMap k) where
  ifoldMap f = foldMap (uncurry f) . unur . LHM.toList