Здесь много настроек. Если вы когда-либо видели последовательность, выровненную по типу, вы можете просмотреть все до строки.
Выровненная по типу последовательность - это все, что выглядит нечетко как
data ConsList c x y where
CNil :: ConsList c x x
Cons :: c x y -> ConsList c y z -> ConsList c x z
Учитывая класс для индексированных функторов с индексом Akey и аппликативных функторов
class IxFunctor f where
ixmap :: (a -> b) -> f x y a -> f x y b
class IxFunctor f => IxApply f where
ixap :: f i j (a -> b) -> f j k a -> f i k b
class IxApply f => IxApplicative f where
ixpure :: a -> f i i a
и двухзначный класс функторов в стиле Макбрайда:
type (f :: q -> r -> *) ~~> (g :: q -> r -> *) =
forall (i :: q) (j :: r) . f i j -> g i j
class TFunctor t where
tmap :: (c ~~> d) -> (t c ~~> t d)
можно описать карты, складки и обходы, которые будут работать для последовательностей, выровненных по строкам:
class TFoldable t where
tfoldMap :: Category d => (c ~~> d) -> t c ~~> d
tfoldMap f = tfoldr (\cij djk -> f cij >>> djk) id
class (TFunctor t, TFoldable t) => TTraversable t where
ttraverse :: IxApplicative f
=> (forall x y . c x y -> f x y (d x y))
-> (t c p q -> f p q (t d p q))
Теперь выясняется, что можно определить версию Data.Functor.Reverse
для последовательностей с выравниванием по типу. Конкретно
newtype Reverse t c x y = Reverse {unReverse :: t (Dual c) y x}
где
newtype Dual c x y = Dual {getDual :: c y x}
Когда тип t
является фактически последовательностью, выровненной по типу, просто дать Reverse t
полный набор операций последовательности с выравниванием по типу.
Фактический вопрос
Что мне не ясно, является ли t
IxTraversable
достаточным для реализации IxTraversable (Reverse t)
. Все, что я пробовал, поражает кирпичную стену. Для стандартных Traversable
s это можно сделать, используя аппликацию Backwards
. Доступен IxBackwards
, но он, похоже, не помогает. Для стандартного Traversable
s можно сбросить содержимое контейнера в список, а затем вернуться из списка. Но это не представляется возможным здесь, потому что нет очевидного способа записи типов на выходе и обеспечения того, что они будут совпадать по пути. Я что-то пропустил или это не-go?
Самый простой старт:
instance IxTraversable t => IxTraversable (Reverse t) where
ttraverse f (Reverse xs) = Reverse `ixmap` _ xs
Это дает мне отверстие типа
t (Dual c) q p -> f p q (t (Dual d) q p)
Очевидная задача состоит в том, что мы имеем t _ q p
, но f p q _
. Поэтому, если есть способ сделать это, нам, по-видимому, нужно как-то придумать f
, который будет переворачивать вещи. Как я уже говорил, там IxBackwards
newtype IxBackwards f y x a = IxBackwards { ixforwards :: f x y a }
но я не вижу, как это помогает.