去年夏天,我考虑了折叠类型对齐序列的概念,asking here如何根据foldr
的类似物实现foldMap
的类似物。 Joachim Breitner能够借助一个棘手的新类型来做到这一点。现在我决定考虑遍历类型对齐序列的概念。我的第一个想法是简单的翻译
class TATraversable t where
ttraverse :: Applicative f
=> (forall x y . c x y -> f (d x y))
-> t c p q -> f (t d p q)
与mapMThrist
包中的thrist
基本相同。不幸的是,这似乎不足以实现
tfoldMap :: Category d
=> (forall x y . c x y -> d x y)
-> f c p q -> d p q
由于Monoid
的{{1}}被Foldable
替换为Category
,TAFoldable
的{{1}}必须被某些内容替换更强。我想出了以下基于Atkey风格的索引应用程序,但感觉有点尴尬,特别是因为索引似乎最终倒退了。基本上,我只是在墙上扔了类型,直到其中一些卡住了。是否有一些更有原则性/可理解的方法?
Applicative
索引的Atkey风格仿函数的多边形版本。我实际上并不需要任何代码的多重性,但我认为任何人实际上使用它会期望它适用于所有类型的幻像。此外,这给了我一个很好的借口来复制这里的定义供参考:
Traversable
基于{-# LANGUAGE ScopedTypeVariables, RankNTypes,
GADTs, PolyKinds #-}
module ITrav where
--Not using this because it's not polykinded
--import Data.Functor.Indexed
import Control.Category
import Prelude hiding (id, (.))
中的方法的类型对齐序列的可映射性概念:
class IxFunctor f where
imap :: (a -> b) -> f j k a -> f j k b
class IxFunctor m => IxPointed m where
ireturn :: a -> m i i a
class IxPointed m => IxApplicative m where
iap :: m i j (a -> b) -> m j k a -> m i k b
我对类型对齐序列的可折叠性概念:
type-aligned
我对类型对齐序列的可穿越性的最佳概念:
class TAMappable t where
tmap :: (forall x y . c x y -> d x y)
-> t c p q -> t d p q
通过遍历绘制机器:
class TAFoldable f where
tfoldMap :: Category d
=> (forall x y . c x y -> d x y)
-> f c p q -> d p q
通过遍历折叠的机器:
class (TAMappable t, TAFoldable t) => TATraversable t where
ttraverse :: IxApplicative m
=> (forall x y . c x y -> m x y (d x y))
-> t c p q -> m p q (t d p q)
证明至少最简单的类型对齐序列允许(有点奇怪)newtype Identity2 x y z = Identity2 {runIdentity2 :: z}
instance IxFunctor Identity2 where
imap f (Identity2 x) = Identity2 (f x)
instance IxPointed Identity2 where
ireturn = Identity2
instance IxApplicative Identity2 where
iap (Identity2 f) (Identity2 x) = Identity2 (f x)
tmapDefault :: TATraversable t => (forall x y . c x y -> d x y) -> t c p q -> t d p q
tmapDefault f = runIdentity2 . ttraverse (Identity2 . f)
实例。
newtype Consty d x y z = Consty { getConsty :: d x y }
instance IxFunctor (Consty d) where
imap _ (Consty x) = Consty x
instance Category d => IxPointed (Consty d) where
ireturn _ = Consty id
instance Category d => IxApplicative (Consty d) where
iap (Consty x) (Consty y) = Consty (y . x)
tfoldMapDefault :: (Category d, TATraversable t) => (forall x y . c x y -> d x y) -> t c p q -> d p q
tfoldMapDefault f = getConsty . ttraverse (Consty . f)
我想我已经找到了一个暗示来源的暗示。我的类型对齐列表以组合链的 end 开头,这使得它与TATraversable
索引顺序对抗。一种选择是用
infixr 5 :::
data TAL :: (k -> k -> *) -> k -> k -> * where
Nil :: TAL c x x
(:::) :: c y z -> TAL c x y -> TAL c x z
instance TAMappable TAL where
tmap = tmapDefault
instance TAFoldable TAL where
tfoldMap = tfoldMapDefault
instance TATraversable TAL where
ttraverse _ Nil = ireturn Nil
ttraverse f (x ::: xs) = imap (flip (:::)) (ttraverse f xs) `iap` f x
的定义
IxApplicative
这使得明显的实例工作:
TAL
但是,说实话,这有点令人讨厌。
答案 0 :(得分:2)
我只想出了一种方法:交换ttraverse
定义中的类型索引:
class (TAMappable t, TAFoldable t) => TATraversable t where
ttraverse :: IxApplicative m
=> (forall x y . c x y -> m y x (d x y))
-> t c p q -> m q p (t d p q)
newtype Consty d y x z = Consty { getConsty :: d x y }
instance Category d => IxApplicative (Consty d) where
iap (Consty x) (Consty y) = Consty (x . y)
然后事情就像我原本希望的那样。不过,我不知道这是不是一个好主意。
幸运的是,似乎无论我采用哪种方式,我都可以使用类似Control.Applicative.Backwards.Backwards
的方式进行反转!
newtype IxBackwards m i j a = IxBackwards {ixForwards :: m j i a}
instance IxFunctor f => IxFunctor (IxBackwards f) where
imap f (IxBackwards x) = IxBackwards (imap f x)
instance IxPointed f => IxPointed (IxBackwards f) where
ireturn = IxBackwards . ireturn
instance IxApplicative f => IxApplicative (IxBackwards f) where
iap (IxBackwards fs) (IxBackwards xs) =
IxBackwards $ imap (flip ($)) xs `iap` fs
ttraverse
类型签名中索引的顺序似乎决定了遍历顺序。如果我不是很困惑,遍历IxBackwards
会颠倒那个顺序:
traverseOpposite :: (IxApplicative m, TATraversable t) => (forall x y . c x y -> m x y (d x y)) -> t c p q -> m p q (t d p q)
traverseOpposite f = ixForwards . ttraverse (IxBackwards . f)