lens
предлагает holesOf
, который является несколько более общей и мощной версией этой гипотетической функции:
holesList :: Traversable t
=> t a -> [(a, a -> t a)]
С учетом контейнера, holesList
создает список элементов контейнера вместе с функциями для замены этих элементов.
Тип holesList
, как и у реальных holesOf
, не позволяет зафиксировать тот факт, что количество произведенных пар будет равно количеству элементов контейнера. Таким образом, гораздо более красивый тип был бы
holes :: Traversable t
=> t a -> t (a, a -> t a)
Мы могли бы реализовать holes
, используя holesList
holes
, чтобы составить список, а затем пересечься в State
чтобы сломать элементы обратно. Но это неудовлетворительно по двум причинам, одно из которых имеет практические последствия:
-
Код разрыва будет иметь недостижимый вызов ошибки для обработки случая, когда список пуст до завершения обхода. Это отвратительно, но, вероятно, не имеет большого значения для тех, кто использует эту функцию.
-
Контейнеры, которые простираются бесконечно влево или внизу слева, не будут работать вообще. Контейнеры, которые простираются очень далеко влево, будут очень неэффективными для обработки.
Мне интересно, есть ли способ обойти эти проблемы. Вполне возможно захватить форму обхода с помощью чего-то вроде Magma
в объективе:
data FT a r where
Pure :: r -> FT a r
Single :: a -> FT a a
Map :: (r -> s) -> FT a r -> FT a s
Ap :: FT a (r -> s) -> FT a r -> FT a s
instance Functor (FT a) where
fmap = Map
instance Applicative (FT a) where
pure = Pure
(<*>) = Ap
runFT :: FT a t -> t
runFT (Pure t) = t
runFT (Single a) = a
runFT (Map f x) = f (runFT x)
runFT (Ap fs xs) = runFT fs (runFT xs)
Теперь у нас есть
runFT . traverse Single = id
traverse Single
делает дерево полным элементов вместе с функциями приложений, необходимых для их сборки в контейнер. Если мы заменим элемент в дереве, мы можем runFT
результат, чтобы получить контейнер с замененным элементом. К сожалению, я застрял: я не знаю, как выглядит следующий шаг.
Смутные мысли: добавление другого параметра типа может помочь изменить типы элементов. Тип Magma
делает что-то вроде этого, и он восходит по крайней мере до тех пор, пока Zemyla комментирует сообщение в блоге Van FunList
о FunList
.