primus-0.1.0.0: src/Primus/Rep.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- |
Module : Primus.Rep
Description : representable methods for use with fixed containers
Copyright : (c) Grant Weyburne, 2022
License : BSD-3
-}
module Primus.Rep (
buildRepL,
buildRepR,
fillRep,
toEnumRep,
izipWithR,
izipWithRF,
ipostscanr,
ipostscanl,
unfoldlRep,
unfoldrRep,
) where
import Data.Bool
import Data.Distributive
import Data.Foldable
import Data.Functor.Rep
import qualified Data.List as L
import qualified Data.List.NonEmpty as N
import Primus.Enum
import Primus.Error
import Primus.Extra
import Primus.Fold
-- | builds a representable from the left using past and future inputs
buildRepL ::
forall f a b.
(Traversable f, Representable f) =>
([Rep f] -> [Rep f] -> b -> Rep f -> (b, a)) ->
b ->
(b, f a)
buildRepL f b0 = histMapL f b0 (tabulate id)
-- | same as 'buildRepL' but associates to the right
buildRepR ::
forall f a b.
(Traversable f, Representable f) =>
([Rep f] -> [Rep f] -> b -> Rep f -> (b, a)) ->
b ->
(b, f a)
buildRepR f b0 = histMapR f b0 (tabulate id)
-- | fill a representable container with a foldable
fillRep ::
forall f a.
(Representable f, Traversable f) =>
[a] ->
Either String ([a], f a)
fillRep = fillTraversable (tabulate id)
-- | load a fixed container with "a"s using the relative position "i"
toEnumRep ::
forall f a.
(Traversable f, Representable f, Enum a, Bounded a) =>
Integer ->
Either String (f a)
toEnumRep = toEnumTraversable (tabulate id)
-- | 'Data.List.zipWith' with rep index
izipWithR ::
Representable f =>
(Rep f -> a -> b -> c) ->
f a ->
f b ->
f c
izipWithR f as bs = tabulate $ \k -> f k (index as k) (index bs k)
-- | 'Control.Monad.zipWithM' with rep index
izipWithRF ::
(Representable f, Distributive g) =>
(Rep f -> a -> b -> g c) ->
f a ->
f b ->
g (f c)
izipWithRF f = collect id .@ izipWithR f
{- | like 'Data.List.scanr'
passes in the 'Rep' index and removes the first element
-}
ipostscanr :: (Representable f, Traversable f) => (Rep f -> a -> b -> b) -> b -> f a -> f b
ipostscanr f c ta =
frp $ fillTraversableExact ta $ N.init $ N.scanr (uncurry f) c xs
where
xs = toList $ imapRep (,) ta
{- | like 'Data.List.scanl'
passes in the 'Rep' index and removes the last element
-}
ipostscanl :: (Representable f, Traversable f) => (Rep f -> b -> a -> b) -> b -> f a -> f b
ipostscanl f c ta =
frp $ fillTraversableExact ta $ N.tail $ N.scanl g c xs
where
xs = imapRep (,) ta
g b (i, a) = f i b a
-- | left/right unfold from the right into a Representable
unfoldlRep
, unfoldrRep ::
(Representable f, Traversable f) =>
(Rep f -> s -> (s, a)) ->
s ->
(s, f a)
unfoldlRep = unfoldRepImpl False
unfoldrRep = unfoldRepImpl True
unfoldRepImpl :: (Representable f, Traversable f) => Bool -> (Rep f -> s -> (s, a)) -> s -> (s, f a)
unfoldRepImpl isright f s = bool L.mapAccumL L.mapAccumR isright (flip f) s (tabulate id)