# OPTIONS_GHC -fno - warn - incomplete - patterns #
# OPTIONS_HADDOCK not - home #
-----------------------------------------------------------------------------
-- |
  Copyright    :   ( c )   2010 - 2021
-- License     :  BSD3
-- Maintainer  :  
-- Stability   :  experimental
  Portability :   GHC only
--
  Combinators used internally by  . AD@
-----------------------------------------------------------------------------
module Numeric.AD.Internal.Combinators
  ( zipWithT
  , zipWithDefaultT
  , withPrimal
  , fromBy
  , takeWhileDifferent
  ) where

import Data.Traversable (mapAccumL)
import Data.Foldable (toList)
import Numeric.AD.Mode
import Numeric.AD.Jacobian

  | Zip a @'Foldable ' f@ with a @'Traversable ' g@ assuming  has at least as many entries as @g@.
zipWithT :: (Foldable f, Traversable g) => (a -> b -> c) -> f a -> g b -> g c
zipWithT f as = snd . mapAccumL f' (toList as)
  where
    f' (a:as') b = (as', f a b)
    f' []      _ = error "zipWithT: second argument contains less entries than third argument"

  | Zip a @'Foldable ' f@ with a @'Traversable ' g@ assuming  , using a default value after @f@ is exhausted .
zipWithDefaultT :: (Foldable f, Traversable g) => a -> (a -> b -> c) -> f a -> g b -> g c
zipWithDefaultT z f as = zipWithT f (toList as ++ repeat z)

  | Used internally to define various '  ' combinators .
withPrimal :: Jacobian t => t -> Scalar t -> t
withPrimal t a = unary (const a) 1 t
{-# INLINE withPrimal #-}

  | Used internally to define various '  ' combinators .
fromBy :: Jacobian t => t -> t -> Int -> Scalar t -> t
fromBy a delta n x = binary (\_ _ -> x) 1 (fromIntegral n) a delta

-- | Used internally to implement functions which truncate lists after the
-- stream of results converge
takeWhileDifferent :: Eq a => [a] -> [a]
takeWhileDifferent (x1:x2:xs) = if x1 == x2
                                  then [x1]
                                  else x1 : takeWhileDifferent (x2:xs)
takeWhileDifferent xs = xs

---------------------------------------------------------------------------
 |
 License     :  BSD3
 Maintainer  :  
 Stability   :  experimental

---------------------------------------------------------------------------
# INLINE withPrimal #
 | Used internally to implement functions which truncate lists after the
 stream of results converge
# OPTIONS_GHC -fno - warn - incomplete - patterns #
# OPTIONS_HADDOCK not - home #
  Copyright    :   ( c )   2010 - 2021
  Portability :   GHC only
  Combinators used internally by  . AD@
module Numeric.AD.Internal.Combinators
  ( zipWithT
  , zipWithDefaultT
  , withPrimal
  , fromBy
  , takeWhileDifferent
  ) where

import Data.Traversable (mapAccumL)
import Data.Foldable (toList)
import Numeric.AD.Mode
import Numeric.AD.Jacobian

  | Zip a @'Foldable ' f@ with a @'Traversable ' g@ assuming  has at least as many entries as @g@.
zipWithT :: (Foldable f, Traversable g) => (a -> b -> c) -> f a -> g b -> g c
zipWithT f as = snd . mapAccumL f' (toList as)
  where
    f' (a:as') b = (as', f a b)
    f' []      _ = error "zipWithT: second argument contains less entries than third argument"

  | Zip a @'Foldable ' f@ with a @'Traversable ' g@ assuming  , using a default value after @f@ is exhausted .
zipWithDefaultT :: (Foldable f, Traversable g) => a -> (a -> b -> c) -> f a -> g b -> g c
zipWithDefaultT z f as = zipWithT f (toList as ++ repeat z)

  | Used internally to define various '  ' combinators .
withPrimal :: Jacobian t => t -> Scalar t -> t
withPrimal t a = unary (const a) 1 t

  | Used internally to define various '  ' combinators .
fromBy :: Jacobian t => t -> t -> Int -> Scalar t -> t
fromBy a delta n x = binary (\_ _ -> x) 1 (fromIntegral n) a delta

takeWhileDifferent :: Eq a => [a] -> [a]
takeWhileDifferent (x1:x2:xs) = if x1 == x2
                                  then [x1]
                                  else x1 : takeWhileDifferent (x2:xs)
takeWhileDifferent xs = xs
