You can assemble this function from parts that are standard or should be. The accepted answer has the correct idea of lightning. My answer about differentiation and comonads gives a general relation to the relevant operations, but let me be specific here.
I define the type of "single-hole item lists" as follows:
data Bwd x = B0 | Bwd x :< x deriving Show type HoleyList x = (Bwd x, [x])
Strictly speaking, I don’t need to enter reverse lists to do this, but I am so easily embarrassed if I have to redo things in my head. (It so happened that HoleyList is a formal derivative of [] .)
Now I can determine what it should be a list item in its context.
type InContext x = (HoleyList x, x)
The idea is that the second component of the pair belongs between the reverse list and the direct list. I can define a function that combines the list together ( upF is upF in the general treatment.)
plug :: InContext x -> [x] plug ((B0, xs), y) = y : xs plug ((xz :< x, xs), y) = plug ((xz, y : xs), x)
I can also define a function that gives all the ways to split a list ( downF , in general).
selections :: [x] -> [InContext x] selections = go B0 where go xz [] = [] go xz (x : xs) = ((xz, xs), x) : go (xz :< x) xs
note that
map snd (selections xs) = xs map plug (selections xs) = map (const xs) xs
And now it’s good for us to follow the Bartek recipe.
selectModify :: (a -> Bool) -> (a -> a) -> [a] -> [[a]] selectModify pf = map (plug . (id *** f)) . filter (p . snd) . selections
That is: filter the selection as a result of the test, apply the function to the element in focus, then reconnect it. If you have equipment for a zipper, it is single-line, and it should work for any differentiable functor, not just lists! The task is completed!
> selectModify ((1 ==) . (`mod` 2)) (2*) [1..10] [[2,2,3,4,5,6,7,8,9,10] ,[1,2,6,4,5,6,7,8,9,10] ,[1,2,3,4,10,6,7,8,9,10] ,[1,2,3,4,5,6,14,8,9,10] ,[1,2,3,4,5,6,7,8,18,10]]