packages feed

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

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeAbstractions #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}

module Control.Monad.Borrow.Pure.Experimental.Reborrowable (
  Reborrowable (..),
  locally,
  locally_,
) where

import Control.Functor.Linear qualified as Control
import Control.Monad.Borrow.Pure.BO
import Prelude.Linear

class Reborrowable bor where
  {- |
  Executes an operation on a borrow in sub lifetime.
  You may need @-XImpredicativeTypes@ extension to use this function.

  Generalization of 'reborrowing'' and 'sharing'' that works for both 'Mut' and 'Share' borrows.
  -}
  locally' ::
    bor α a %1 ->
    (forall β. bor (β /\ α) a %1 -> BO (β /\ α') (After β r)) %1 ->
    BO α' (r, bor α a)

instance Reborrowable Mut where
  {-# SPECIALIZE instance Reborrowable Mut #-}
  locally' = reborrowing'
  {-# INLINE locally' #-}

instance Reborrowable Share where
  {-# SPECIALIZE instance Reborrowable Share #-}
  locally' shr k = Control.do
    let %1 !(Ur sh) = move shr
    (,sh) Control.<$> srunBO (k (upcast sh))
  {-# INLINE locally' #-}

locally ::
  (Reborrowable bor) =>
  bor α a %1 ->
  (forall β. bor (β /\ α) a %1 -> BO (β /\ α') r) %1 ->
  BO α' (r, bor α a)
{-# INLINE locally #-}
locally bor k = locally' bor \mut -> Control.pure Control.<$> k mut

locally_ ::
  (Reborrowable bor, Consumable r) =>
  bor α a %1 ->
  (forall β. bor (β /\ α) a %1 -> BO (β /\ α') r) %1 ->
  BO α' (bor α a)
{-# INLINE locally_ #-}
locally_ bor k = uncurry lseq Control.<$> locally bor k