{-# LANGUAGE Safe #-}
-- NB: We disable @StrictData@ here in order for `Cofix` to be lazy. I don’t
--     think there is any way to explicitly add @~@ patterns that has the
--     correct semantics.
{-# LANGUAGE NoStrictData #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}

-- | This module only exists to restrict the scope of @NoStrictData@. Everything
--    is re-exported via "Yaya.Fold".
module Yaya.Fold.Native.Internal
  ( Cofix (Cofix, unCofix),
  )
where

import "base" Control.Category (Category ((.)))
import "base" Data.Functor (Functor (fmap))
import "this" Yaya.Fold
  ( Corecursive (ana),
    Projectable (project),
    Steppable (embed),
  )

-- | A fixed-point constructor that uses Haskell's built-in recursion. This is
--   lazy/corecursive.
data Cofix f = Cofix {forall (f :: * -> *). Cofix f -> f (Cofix f)
unCofix :: f (Cofix f)}

{-# HLINT ignore Cofix "Use newtype instead of data" #-}

instance Projectable (->) (Cofix f) f where
  project :: Coalgebra (->) f (Cofix f)
project = Coalgebra (->) f (Cofix f)
forall (f :: * -> *). Cofix f -> f (Cofix f)
unCofix

instance Steppable (->) (Cofix f) f where
  embed :: Algebra (->) f (Cofix f)
embed = Algebra (->) f (Cofix f)
forall (f :: * -> *). Algebra (->) f (Cofix f)
Cofix

instance (Functor f) => Corecursive (->) (Cofix f) f where
  ana :: forall a. Coalgebra (->) f a -> a -> Cofix f
ana Coalgebra (->) f a
φ = Algebra (->) f (Cofix f)
forall {k} (c :: k -> k -> *) (t :: k) (f :: k -> k).
Steppable c t f =>
Algebra c f t
embed Algebra (->) f (Cofix f) -> (a -> f (Cofix f)) -> a -> Cofix f
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (a -> Cofix f) -> f a -> f (Cofix f)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Coalgebra (->) f a -> a -> Cofix f
forall a. Coalgebra (->) f a -> a -> Cofix f
forall {k} {k1} (c :: k -> k1 -> *) (t :: k1) (f :: k -> k1)
       (a :: k).
Corecursive c t f =>
Coalgebra c f a -> c a t
ana Coalgebra (->) f a
φ) (f a -> f (Cofix f)) -> Coalgebra (->) f a -> a -> f (Cofix f)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Coalgebra (->) f a
φ