Missing Haskell primitive to apply a function to each element of a list successively?
It seems like the simplest version of this is direct recursion:
sap :: (a -> a) -> [a] -> [[a]]
sap _ [] = []
sap f (x:xs) = (f x : xs) : map (x:) (sap f xs)
One possible exploration of this is as a paramorphism, which gives access to the recursive result and the unprocessed remainder together.
sap f = para step where
step Nil = []
step (Cons x (xs, rest)) = (f x : xs) : map (x:) rest
(Not checked, might have silly errors)
I don't see that as a huge improvement though. I don't see any deep insights in that decomposition of recursion from the problem itself.
For that, well... I've used holesOf
for a generalized version of this in the past.
sap :: Traversable t => (a -> a) -> t a -> [t a]
sap f = map (peeks f) . holesOf traverse
Now that definitely says something. It has generalized the type to work on all instances of Traversable
. On the other hand, the theoretical chunks involved were so overpowered for the end result that I'm not sure what it actually is that it says. On the third(?) hand, it looks pretty.
Or is there a way to write it that is so short and simple that it does not even deserve to be a separate function, putting it below the so-called Fairbairn threshold?
This. The functionality is rarely needed, and the (a -> a)
argument doesn't make for a very generic application.
A short and simple implementation can be achieved with list recursion:
sap :: (a -> a) -> [a] -> [[a]]
sap _ [] = []
sap f (x:xs) = (f x:xs):((x:) <$> sap f xs)
I don't think it exists anywhere, although proving it negatively is of course impossible.. Another way to write sap
, which I would probably prefer over using foldr
,
sap f ls = zipWith (alterWith f) [0..] (iterate ls)
where alterWith f i ls = take i ls ++ f (ls !! i) : drop (i+1) ls
alterWith
is available as adjust
in https://hackage.haskell.org/package/fft-0.1.8.6/docs/Math-FFT-Base.html#v:adjust, but I would very much not bring something so heavyweight in for that function. I often have something like alterWith
defined in a project already, though, and if so that allows sap
to be elided in favor of the call to zipWith above.