Предположим, у меня есть Tree
тип:
{-# LANGUAGE DeriveFoldable, DeriveFunctor #-}
data Tree a = Leaf | Branch (Tree a) a (Tree a) deriving(Functor,Foldable)
instance Traversable Tree where -- equivalent to the one I could derive, but written out for clarity
traverse _ Leaf = pure Leaf
traverse f (Branch l x r) = Branch <$> traverse f l <*> f x <*> traverse f r
Легко написать функцию для вычисления максимальной глубины вещей внутри этого конкретного типа:
depth Leaf = 0
depth (Branch l _ r) = 1 + max (depth l) (depth r)
Но этоНе так просто рассчитать максимальную глубину вещей внутри произвольного Traversable
.Я уже знаю, что просто Functor
недостаточно для этого, поскольку вы не получаете информации о «положении» вещей внутри них через fmap
, и я также уже знаю, что просто Foldable
недостаточно дляэто, поскольку foldr
и foldMap
оба дают столько структуры, сколько имеют списки.Traversable
может быть, тем не менее, потому что он более общий, чем Functor
и Foldable
.
Однако, после некоторых экспериментов, я не думаю, что есть способ сделать это с Traversable
или.Вот моя логика до сих пор.Рассмотрим эти два дерева:
fooTree = Branch (Branch Leaf () Leaf) () (Branch Leaf () Leaf)
barTree = Branch (Branch Leaf () (Branch Leaf () Leaf)) () Leaf
Теперь traverse (\() -> thingy) fooTree
равно:
Branch <$> (Branch <$> pure Leaf <*> thingy <*> pure Leaf) <*> thingy <*> (Branch <$> pure Leaf <*> thingy <*> pure Leaf)
После большого количества использования Применимых законов и некоторого упрощения это становится:
(\x y z -> Branch (Branch Leaf x Leaf) y (Branch Leaf z Leaf)) <$> thingy <*> thingy <*> thingy
Аналогично, traverse (\() -> thingy) barTree
- это:
Branch <$> (Branch <$> pure Leaf <*> thingy <*> (Branch <$> pure Leaf <*> thingy <*> pure Leaf)) <*> thingy <*> pure Leaf
После большого количества использования Применимых законов и некоторого упрощения это становится:
(\x y z -> Branch (Branch Leaf x (Branch Leaf y Leaf)) z Leaf) <$> thingy <*> thingy <*> thingy
Сейчас traverse (\() -> thingy) fooTree
и traverse (\() -> thingy) barTree
похоже, что они имеют одинаковую «форму» (единственное отличие - лямбда в начале, и даже их типы одинаковы), но они пришли с деревьев, которые имеют разную глубину.Это заставляет меня поверить, что невозможно найти глубину в терминах traverse
, но я не уверен на 100% в этом, и я не уверен, как объяснить это строго.
Я правчто это невозможно?Если так, то как это можно объяснить строго?Если нет, то как бы вы это реализовали?