packages feed

yaftee-conduit-0.1.0.1: src/Control/Monad/Yaftee/Pipe/Tools.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
{-# LANGUAGE RequiredTypeArguments #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Control.Monad.Yaftee.Pipe.Tools (

	-- * CONVERT

	convert, convert', convert'',

	-- * FILTER

	filter, filter',

	-- * EITHER

	checkRight, skipLeft1,

	-- * LENGTH

	lengthRun, length, Length,

	-- * SCAN

	scanl,

	-- * DEVIDE

	devideRun, devide, devideNs, Devide

	) where

import Prelude hiding (length, filter, scanl)
import Prelude qualified as P
import Control.Monad
import Control.Monad.Fix
import Control.Monad.Yaftee.Eff qualified as Eff
import Control.Monad.Yaftee.Pipe qualified as Pipe
import Control.Monad.Yaftee.State qualified as State
import Control.Monad.Yaftee.Except qualified as Except
import Control.HigherOpenUnion qualified as U
import Data.HigherFunctor qualified as HFunctor
import Data.Bits
import Data.Bool

convert :: U.Member Pipe.P effs => (a -> b) -> Eff.E effs a b r
convert f = fix \go -> Pipe.await >>= ((>> go) . Pipe.yield . f)

convert' :: U.Member Pipe.P effs => (a -> b) -> Eff.E effs a b ()
convert' f = fix \go -> Pipe.isMore
	>>= bool (pure ()) (Pipe.await >>= ((>> go) . Pipe.yield . f))

convert'' :: U.Member Pipe.P es => (Bool -> a -> b) -> a -> Eff.E es a b ()
convert'' f = fix \go p -> Pipe.isMore >>= bool
	(Pipe.yield (f True p))
	(Pipe.await >>= \x -> ((>> go x) . Pipe.yield $ f False p))

filter :: U.Member Pipe.P es => (a -> Maybe b) -> Eff.E es a b r
filter f = fix \go -> Pipe.await >>= \x -> case f x of
	Nothing -> go
	Just y -> Pipe.yield y >> go

filter' :: U.Member Pipe.P es => (a -> Maybe b) -> Eff.E es a b ()
filter' f = fix \go -> Pipe.isMore
	>>= bool (pure ()) (Pipe.await >>= \x -> case f x of
		Nothing -> go
		Just y -> Pipe.yield y >> go)

checkRight :: (U.Member Pipe.P es, U.Member (Except.E String) es) =>
	Eff.E es (Either a b) b r
checkRight = fix \go -> Pipe.await >>= (>> go)
	. either (const $ Except.throw "(Left _) exist") (Pipe.yield)

skipLeft1 :: (U.Member Pipe.P es, U.Member (Except.E String) es) =>
	Eff.E es (Either a b) o b
skipLeft1 = Pipe.await >>= \case
	Left _ -> Pipe.await >>= \case
		Left _ -> Except.throw @String "Not Right"
		Right x -> pure x
	Right x -> pure x

lengthRun :: forall nm es i o a . HFunctor.Loose (U.U es) =>
	Eff.E (State.Named nm Length ': es) i o a -> Eff.E es i o (a, Length)
lengthRun = (`State.runN` (0 :: Length))

length :: forall nm -> (
	Foldable t,
	U.Member Pipe.P es, U.Member (State.Named nm Length) es ) =>
	Eff.E es (t a) (t a) r
length nm = forever $ Pipe.await >>= \s ->
	State.modifyN nm (+ Length (P.length s)) >> Pipe.yield s

newtype Length = Length { unLength :: Int }
	deriving (Show, Eq, Bits, FiniteBits, Ord, Enum, Num, Real, Integral)

scanl :: U.Member Pipe.P es => (b -> a -> b) -> b -> Eff.E es a b r
scanl op =
	fix \go v -> (v `op`) <$>  Pipe.await >>= \v' -> Pipe.yield v' >> go v'

devideRun :: forall nm m es i o r . (P.Monoid m, HFunctor.Loose (U.U es)) =>
	Eff.E (State.Named nm (Devide m) ': es) i o r ->
	Eff.E es i o (r, Devide m)
devideRun = flip (State.runN @nm) (Devide mempty)

devideNs :: forall nm -> (
	Semigroup m,
	U.Member Pipe.P es, U.Member (State.Named nm (Devide m)) es ) =>
	(Int -> m -> Maybe (m, m)) -> m -> [Int] -> Eff.E es m m ()
devideNs nm sp bs0 ns0 = do
	State.putN nm $ Devide bs0
	($ ns0) $ fix \go -> \case
		[] -> pure ()
		n : ns -> do
			Pipe.yield =<< getInput nm sp n
			go ns

devide :: forall nm -> (
	Eq m, P.Monoid m,
	U.Member Pipe.P es, U.Member (State.Named nm (Devide m)) es ) =>
	(Int -> m -> Maybe (m, m)) -> m -> Int -> Eff.E es m m ()
devide nm sp bs0 n = do
	State.putN nm $ Devide bs0
	fix \go -> do
		bs <- getInput' nm sp n
		if bs == mempty then pure () else Pipe.yield bs >> go

getInput' :: forall m es o . forall nm -> (
	P.Monoid m,
	U.Member Pipe.P es, U.Member (State.Named nm (Devide m)) es ) =>
	(Int -> m -> Maybe (m, m)) -> Int -> Eff.E es m o m
getInput' nm sp n = State.getN nm >>= \(Devide bs) -> case sp n bs of
	Nothing -> readMore' nm >>= bool
		(unDevide <$> (State.getN nm <* State.putN @(Devide m) nm (Devide mempty)))
		(getInput' nm sp n)
	Just (t, d) -> t <$ State.putN nm (Devide d)

readMore' :: forall nm -> (
	Semigroup mono, U.Member Pipe.P es,
	U.Member (State.Named nm (Devide mono)) es ) =>
	Eff.E es mono o Bool
readMore' nm = Pipe.awaitMaybe >>= \case
	Nothing -> pure False
	Just xs -> True <$ State.modifyN nm (Devide . (<> xs) . unDevide)

getInput :: forall nm -> (
	Semigroup m,
	U.Member Pipe.P es, U.Member (State.Named nm (Devide m)) es ) =>
	(Int -> m -> Maybe (m, m)) -> Int -> Eff.E es m o m
getInput nm sp n = State.getN nm >>= \(Devide bs) -> case sp n bs of
	Nothing -> readMore nm >> getInput nm sp n
	Just (t, d) -> t <$ State.putN nm (Devide d)

readMore :: forall nm -> (
	Semigroup mono, U.Member Pipe.P es,
	U.Member (State.Named nm (Devide mono)) es ) =>
	Eff.E es mono o ()
readMore nm =
	Pipe.await >>= \xs -> State.modifyN nm (Devide . (<> xs) . unDevide)

newtype Devide m = Devide { unDevide :: m } deriving Show