Somebody suggested I post this here if I wanted feedback.
So I was thinking about the ReverseState monad I saw mentioned on r/haskell a couple days ago, and playing around with the concept of information flowing two directions when I came up with this function:
bifold :: (l -> a -> r -> (r,l)) -> (l,r) -> [a] -> (r,l)
bifold _ (l,r) [] = (r,l)
bifold f (l,r) (a:as) = (ra,las)
where (ras,las) = bifold f (la,r) as
(ra,la) = f l a ras
(I'm sure someone else has come up with this before, so I'll just say I discovered it, not invented it).
Basically, it's a simultaneous left and right fold, passing one value from the start of the list toward the end, and one from the end toward the start.
It lets you do some interesting stuff, like filter based on positionor other left-dependent information:
evenIndexed :: [a] -> [a]
evenIndexed = fst . bifold alternate (0,[])
where alternate 0 x xs = (x:xs, 1)
alternate 1 _ xs = (xs, 0)
maximums :: (Ord a) => [a] -> [a]
maximums [] = []
maximums (a:as) = a : (fst $ bifold (\m a l -> if a > m then (a:l,a) else (l,m)) (a,[]) as)
As long as you don't examine the left-to-right value, it can still work on infinite lists:
ghci> take 20 $ evenIndexed [0..]
[0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38]