module NumericPrelude.List where

import Data.List.HT (switchL, switchR, )

{- * Zip lists -}

{- | zip two lists using an arbitrary function, the shorter list is padded -}
-> (a -> a -> b)   {-^ function applied to corresponding elements of the lists -}
-> [a]
-> [a]
-> [b]
let aux l []          = map (\x -> f x z) l
aux [] l          = map (\y -> f z y) l
aux (x:xs) (y:ys) = f x y : aux xs ys
in  aux

{-# INLINE zipWithOverlap #-}
zipWithOverlap :: (a -> c) -> (b -> c) -> (a -> b -> c) -> [a] -> [b] -> [c]
zipWithOverlap fa fb fab =
let aux (x:xs) (y:ys) = fab x y : aux xs ys
aux xs [] = map fa xs
aux [] ys = map fb ys
in  aux

{-
This is exported as Checked.zipWith.
We need to define it here in order to prevent an import cycle.
-}
zipWithChecked
:: (a -> b -> c)   {-^ function applied to corresponding elements of the lists -}
-> [a]
-> [b]
-> [c]
zipWithChecked f =
let aux (x:xs) (y:ys) = f x y : aux xs ys
aux []     []     = []
aux _      _      = error "Checked.zipWith: lists must have the same length"
in  aux

{- |
Apply a function to the last element of a list.
If the list is empty, nothing changes.
-}
{-# INLINE mapLast #-}
mapLast :: (a -> a) -> [a] -> [a]
mapLast f =
switchL []
(\x xs ->
uncurry (:) \$
foldr (\x1 k x0 -> (x0, uncurry (:) (k x1)))
(\x0 -> (f x0, [])) xs x)

mapLast' :: (a -> a) -> [a] -> [a]
mapLast' f =
let recourse [] = [] -- behaviour as needed in powerBasis
-- otherwise: error "mapLast: empty list"
recourse (x:xs) =
uncurry (:) \$
if null xs
then (f x, [])
else (x, recourse xs)
in  recourse

mapLast'' :: (a -> a) -> [a] -> [a]
mapLast'' f =
switchR [] (\xs x -> xs ++ [f x])