-- |
-- Module      :  Data.SubG.Unfold
-- Copyright   :  (c) OleksandrZhabenko 2021
-- License     :  MIT
-- Stability   :  Experimental
-- Maintainer  :  olexandr543@yahoo.com
--
-- Generalization of the 'Data.List.unfoldr' for the data type that has 'InsertLeft' and 'Monoid' instances.
-- Inspired by: https://www.works-hub.com/learn/number-anamorphisms-aka-unfolds-explained-50e1a by Marty Stumpf.

module Data.SubG.Unfold (
  unfoldG
  , iterateG
) where

import Data.SubG
import Data.Maybe (isJust, fromJust)
import Data.Monoid

-- | Inspired by: https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.OldList.html#words
-- and: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Also inspired by: https://www.works-hub.com/learn/number-anamorphisms-aka-unfolds-explained-50e1a by Marty Stumpf.
-- Generalizes the 'Data.List.unfoldr' function not only for lists, but for the data type that has 'InsertLeft' and 'Monoid' instances.
unfoldG :: (InsertLeft t a, Monoid (t a)) => (a -> Maybe (a, a)) -> a -> t a
unfoldG :: (a -> Maybe (a, a)) -> a -> t a
unfoldG a -> Maybe (a, a)
p a
x
 | Maybe (a, a) -> Bool
forall a. Maybe a -> Bool
isJust (a -> Maybe (a, a)
p a
x) = a
x a -> t a -> t a
forall (t :: * -> *) a. InsertLeft t a => a -> t a -> t a
%@ (a -> Maybe (a, a)) -> a -> t a
forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Maybe (a, a)) -> a -> t a
unfoldG a -> Maybe (a, a)
p ((a, a) -> a
forall a b. (a, b) -> b
snd ((a, a) -> a) -> (a -> (a, a)) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe (a, a) -> (a, a)
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe (a, a) -> (a, a)) -> (a -> Maybe (a, a)) -> a -> (a, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Maybe (a, a)
p (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ a
x)
 | Bool
otherwise = t a
forall a. Monoid a => a
mempty

-- | Inspired by: https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.OldList.html#words
-- and: Graham Hutton. A tutorial on the universality and expressiveness of fold. /J. Functional Programming/ 9 (4): 355–372, July 1999.
-- that is available at the URL: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
-- Also inspired by: https://www.works-hub.com/learn/number-anamorphisms-aka-unfolds-explained-50e1a by Marty Stumpf.
-- Generalizes the 'Prelude.iterate' function not only for lists, but for the data type that has 'InsertLeft' and 'Monoid' instances.
iterateG :: (InsertLeft t a, Monoid (t a)) => (a -> a) -> a -> t a
iterateG :: (a -> a) -> a -> t a
iterateG a -> a
f = (a -> Maybe (a, a)) -> a -> t a
forall (t :: * -> *) a.
(InsertLeft t a, Monoid (t a)) =>
(a -> Maybe (a, a)) -> a -> t a
unfoldG (\a
x -> (a, a) -> Maybe (a, a)
forall a. a -> Maybe a
Just (a
x, a -> a
f a
x))
{-# INLINE iterateG #-}