Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions indexed-traversable/Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 0.1.6 [unreleased]

- Document the laws of `FunctorWithIndex`, `FoldableWithIndex`, and
`TraversableWithIndex`: the `fmap`/`foldMap`/`traverse` compatibility laws
and agreement with `imapDefault`/`ifoldMapDefault`.

# 0.1.5 [2026-05-07]

- Use automatic flags for compatibility conditionals
Expand Down
35 changes: 35 additions & 0 deletions indexed-traversable/src/WithIndex.hs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ import CoerceCompat
-- 'imap' f '.' 'imap' g ≡ 'imap' (\\i -> f i '.' g i)
-- 'imap' (\\_ a -> a) ≡ 'id'
-- @
--
-- The index must be compatible with the underlying 'Functor': forgetting the
-- index recovers 'fmap'.
--
-- @
-- 'fmap' f ≡ 'imap' ('const' f)
-- @
class Functor f => FunctorWithIndex i f | f -> i where
-- | Map with access to the index.
imap :: (i -> a -> b) -> f a -> f b
Expand All @@ -86,6 +93,16 @@ imapDefault f = runIdentity #. itraverse (Identity #.. f)
-------------------------------------------------------------------------------

-- | A container that supports folding with an additional index.
--
-- The index must be compatible with the underlying 'Foldable': forgetting the
-- index recovers 'foldMap'.
--
-- @
-- 'foldMap' f ≡ 'ifoldMap' ('const' f)
-- @
--
-- When the same type is also a 'FunctorWithIndex' or 'TraversableWithIndex',
-- all three agree on the index assigned to each element.
class Foldable f => FoldableWithIndex i f | f -> i where
--
-- | Fold a container by mapping value to an arbitrary 'Monoid' with access to the index @i@.
Expand Down Expand Up @@ -230,6 +247,24 @@ class (Foldable1 f, FoldableWithIndex i f) => Foldable1WithIndex i f | f -> i wh
-- 'itraverse' ('const' 'Identity') ≡ 'Identity'
-- 'fmap' ('itraverse' f) '.' 'itraverse' g ≡ 'Data.Functor.Compose.getCompose' '.' 'itraverse' (\\i -> 'Data.Functor.Compose.Compose' '.' 'fmap' (f i) '.' g i)
-- @
--
-- The index must be compatible with the underlying 'Traversable': forgetting
-- the index recovers 'traverse'.
--
-- @
-- 'traverse' f ≡ 'itraverse' ('const' f)
-- @
--
-- The 'FunctorWithIndex' and 'FoldableWithIndex' instances must agree with the
-- ones induced by 'itraverse':
--
-- @
-- 'imap' ≡ 'imapDefault'
-- 'ifoldMap' ≡ 'ifoldMapDefault'
-- @
--
-- so 'itraverse' visits every element exactly once, in order, pairing it with
-- the same index used by 'imap' and 'ifoldMap'.
class (FunctorWithIndex i t, FoldableWithIndex i t, Traversable t) => TraversableWithIndex i t | t -> i where
-- | Traverse an indexed container.
--
Expand Down