Traversable to Traversable which traverse only element with specified index

235 views Asked by At

I wonder if it possible to construct following function

ix :: (Applicative a, Traversable t) => Int -> (v -> a v) -> (t v -> a (t v))

Which uses pure for all elements except i-th for which v -> a v is used (Traversal over value with specified index).

Basically I am trying to generalize following function for all traversables. Or is it impossible? Traversable can always be converted to Zipper and I thought it could be generalized.

idx _ _ []     = pure []
idx 0 f (x:xs) = (:xs) <$> f x
idx i f (x:xs) = (x:)  <$> idx (i - 1) f xs
1

There are 1 answers

0
kosmikus On BEST ANSWER

Here's an ad-hoc attempt. I'm sure there are more elegant options:

import Control.Applicative
import Control.Monad.State
import Data.Traversable as T

ix :: (Applicative a, Traversable t) => Int -> (v -> a v) -> (t v -> a (t v))
ix i f =
    sequenceA
  . flip evalState 0
  . T.mapM (\ x -> do
                     j <- get
                     put (j + 1)
                     if i == j then return (f x)
                               else return (pure x))