lude

Haskell prelude alternative
git clone git://git.rr3.xyz/lude | git clone gits://git.rr3.xyz/lude
Log | Files | Refs | README | LICENSE

commit 5f4d78ab7400b020beea411d7d1cc3144a93c736
parent 5724351a8a85cd9d3e272642b2c37eeb096d6f83
Author: Robert Russell <robert@rr3.xyz>
Date:   Mon,  5 Oct 2026 10:04:52 -0700

Pair: add tentative combinators for Repr-generic pair manipulations

Diffstat:
Msrc/Lude/Algebra/Category/Bifunctor.hs | 7+------
Msrc/Lude/Algebra/Category/Core.hs | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Lude/Function.hs | 7-------
Msrc/Lude/Haskell/Category.hs | 4++--
Msrc/Lude/Pair.hs | 170++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
5 files changed, 202 insertions(+), 34 deletions(-)

diff --git a/src/Lude/Algebra/Category/Bifunctor.hs b/src/Lude/Algebra/Category/Bifunctor.hs @@ -19,6 +19,7 @@ import Lude.Algebra.Category.Core import Lude.Algebra.Category.Iso import Lude.Algebra.Category.Terminal import Lude.Haskell +import Lude.Pair -- TODO: Read Conor McBride's paper on bifunctors and decide what abstractions -- are worth providing here. @@ -162,12 +163,6 @@ class (MonoidalFunctorialOn p (Prod p), HasTerminalObject p, Terminal p ~ Monid -------------------------------------------------------------------------------- -- TODO: Temp -type Pair :: Type -> Type -> Type -data Pair a b = MkPair a b - -instance Functorial (Pair a) where map f = \(MkPair x y) -> MkPair x (f y) -instance Functorial Pair where map f = Naturally \(MkPair x y) -> MkPair (f x) y - instance SemigroupalFunctorial Pair where assoc = MkIso to fro where diff --git a/src/Lude/Algebra/Category/Core.hs b/src/Lude/Algebra/Category/Core.hs @@ -31,6 +31,7 @@ import Data.Coerce import Prelude qualified as Base import Lude.Constraint.Predicate +import Lude.Function import Lude.Haskell import Lude.IO import Lude.List @@ -235,6 +236,53 @@ instance Functorial Given where type Cod Given = Entailment map = mapGiven +-- TODO: We'll need some map aliases for NT-valued functors to make these usable... +instance Functorial (Tuple1) where map z = \(MkTuple1 a) -> MkTuple1 (z a) +instance Functorial (Tuple2 a) where map z = \(a, b) -> (a, z b) +instance Functorial (Tuple2) where map z = Naturally \(a, b) -> (z a, b) +instance Functorial (Tuple3 a b) where map z = \(a, b, c) -> (a, b, z c) +instance Functorial (Tuple3 a) where map z = Naturally \(a, b, c) -> (a, z b, c) +instance Functorial (Tuple3) where map z = Naturally $ Naturally \(a, b, c) -> (z a, b, c) +instance Functorial (Tuple4 a b c) where map z = \(a, b, c, d) -> (a, b, c, z d) +instance Functorial (Tuple4 a b) where map z = Naturally \(a, b, c, d) -> (a, b, z c, d) +instance Functorial (Tuple4 a) where map z = Naturally $ Naturally \(a, b, c, d) -> (a, z b, c, d) +instance Functorial (Tuple4) where map z = Naturally $ Naturally $ Naturally \(a, b, c, d) -> (z a, b, c, d) +instance Functorial (Tuple5 a b c d) where map z = \(a, b, c, d, e) -> (a, b, c, d, z e) +instance Functorial (Tuple5 a b c) where map z = Naturally $ \(a, b, c, d, e) -> (a, b, c, z d, e) +instance Functorial (Tuple5 a b) where map z = Naturally $ Naturally \(a, b, c, d, e) -> (a, b, z c, d, e) +instance Functorial (Tuple5 a) where map z = Naturally $ Naturally $ Naturally \(a, b, c, d, e) -> (a, z b, c, d, e) +instance Functorial (Tuple5) where map z = Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e) -> (z a, b, c, d, e) +instance Functorial (Tuple6 a b c d e) where map z = \(a, b, c, d, e, f) -> (a, b, c, d, e, z f) +instance Functorial (Tuple6 a b c d) where map z = Naturally $ \(a, b, c, d, e, f) -> (a, b, c, d, z e, f) +instance Functorial (Tuple6 a b c) where map z = Naturally $ Naturally $ \(a, b, c, d, e, f) -> (a, b, c, z d, e, f) +instance Functorial (Tuple6 a b) where map z = Naturally $ Naturally $ Naturally \(a, b, c, d, e, f) -> (a, b, z c, d, e, f) +instance Functorial (Tuple6 a) where map z = Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f) -> (a, z b, c, d, e, f) +instance Functorial (Tuple6) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f) -> (z a, b, c, d, e, f) +instance Functorial (Tuple7 a b c d e f) where map z = \(a, b, c, d, e, f, g) -> (a, b, c, d, e, f, z g) +instance Functorial (Tuple7 a b c d e) where map z = Naturally $ \(a, b, c, d, e, f, g) -> (a, b, c, d, e, z f, g) +instance Functorial (Tuple7 a b c d) where map z = Naturally $ Naturally $ \(a, b, c, d, e, f, g) -> (a, b, c, d, z e, f, g) +instance Functorial (Tuple7 a b c) where map z = Naturally $ Naturally $ Naturally $ \(a, b, c, d, e, f, g) -> (a, b, c, z d, e, f, g) +instance Functorial (Tuple7 a b) where map z = Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g) -> (a, b, z c, d, e, f, g) +instance Functorial (Tuple7 a) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g) -> (a, z b, c, d, e, f, g) +instance Functorial (Tuple7) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g) -> (z a, b, c, d, e, f, g) +instance Functorial (Tuple8 a b c d e f g) where map z = \(a, b, c, d, e, f, g, h) -> (a, b, c, d, e, f, g, z h) +instance Functorial (Tuple8 a b c d e f) where map z = Naturally $ \(a, b, c, d, e, f, g, h) -> (a, b, c, d, e, f, z g, h) +instance Functorial (Tuple8 a b c d e) where map z = Naturally $ Naturally $ \(a, b, c, d, e, f, g, h) -> (a, b, c, d, e, z f, g, h) +instance Functorial (Tuple8 a b c d) where map z = Naturally $ Naturally $ Naturally $ \(a, b, c, d, e, f, g, h) -> (a, b, c, d, z e, f, g, h) +instance Functorial (Tuple8 a b c) where map z = Naturally $ Naturally $ Naturally $ Naturally $ \(a, b, c, d, e, f, g, h) -> (a, b, c, z d, e, f, g, h) +instance Functorial (Tuple8 a b) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g, h) -> (a, b, z c, d, e, f, g, h) +instance Functorial (Tuple8 a) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g, h) -> (a, z b, c, d, e, f, g, h) +instance Functorial (Tuple8) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g, h) -> (z a, b, c, d, e, f, g, h) +instance Functorial (Tuple9 a b c d e f g h) where map z = \(a, b, c, d, e, f, g, h, i) -> (a, b, c, d, e, f, g, h, z i) +instance Functorial (Tuple9 a b c d e f g) where map z = Naturally $ \(a, b, c, d, e, f, g, h, i) -> (a, b, c, d, e, f, g, z h, i) +instance Functorial (Tuple9 a b c d e f) where map z = Naturally $ Naturally $ \(a, b, c, d, e, f, g, h, i) -> (a, b, c, d, e, f, z g, h, i) +instance Functorial (Tuple9 a b c d e) where map z = Naturally $ Naturally $ Naturally $ \(a, b, c, d, e, f, g, h, i) -> (a, b, c, d, e, z f, g, h, i) +instance Functorial (Tuple9 a b c d) where map z = Naturally $ Naturally $ Naturally $ Naturally $ \(a, b, c, d, e, f, g, h, i) -> (a, b, c, d, z e, f, g, h, i) +instance Functorial (Tuple9 a b c) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ \(a, b, c, d, e, f, g, h, i) -> (a, b, c, z d, e, f, g, h, i) +instance Functorial (Tuple9 a b) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g, h, i) -> (a, b, z c, d, e, f, g, h, i) +instance Functorial (Tuple9 a) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g, h, i) -> (a, z b, c, d, e, f, g, h, i) +instance Functorial (Tuple9) where map z = Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally $ Naturally \(a, b, c, d, e, f, g, h, i) -> (z a, b, c, d, e, f, g, h, i) + -------------------------------------------------------------------------------- -- Interop diff --git a/src/Lude/Function.hs b/src/Lude/Function.hs @@ -6,7 +6,6 @@ module Lude.Function ( const, flip, on, - fork, compose00#, (.#), compose00, @@ -68,12 +67,6 @@ on on f g = lam2# \x y -> app2# f (app# g x) (app# g y) {-# INLINE on #-} -fork - :: forall {r :: Repr} (a :: Type# r) {s :: Repr} (b :: Type# s) {t :: Repr} (c :: Type# t) {u :: Repr} (d :: Type# u) - . (Functional# r, Functional# s, Functional# t) => (b -> c -> d) -> (a -> b) -> (a -> c) -> (a -> d) -fork f g h = lam# \x -> app2# f (app# g x) (app# h x) -{-# INLINE fork #-} - -------------------------------------------------------------------------------- -- Composition diff --git a/src/Lude/Haskell/Category.hs b/src/Lude/Haskell/Category.hs @@ -82,11 +82,11 @@ type Function :: Cat Type type Function = Function# Repr.BoxL -- | Natural transformations to `Function`/`->` -type (~>) :: forall i (r :: Repr). Cat (i -> Type# r) +type (~>) :: forall i (r :: Repr) (s :: Repr). (i -> Type# r) -> (i -> Type# s) -> Type type f ~> g = forall x. f x -> g x -- | Binatural transformations to `Function`/`->` -type (~~>) :: forall i j (r :: Repr). Cat (i -> j -> Type# r) +type (~~>) :: forall i j (r :: Repr) (s :: Repr). (i -> j -> Type# r) -> (i -> j -> Type# s) -> Type type f ~~> g = forall x y. f x y -> g x y identityFunction :: forall {r :: Repr} (a :: Type# r). (Functional# r) => a -> a diff --git a/src/Lude/Pair.hs b/src/Lude/Pair.hs @@ -1,42 +1,174 @@ module Lude.Pair ( Pair, + MkPair, pattern MkPair, type (*), - fst, - snd, - Fst, - Snd, + outl, + outr, + dup, + swap, + curry, + uncurry, + Outl, + Outr, + -- + fbimap, + flmap, + frmap, + fbmap, + fbmap1, + foutl, + foutr, + fdup, + fswap, ) where +import Data.Tuple qualified as Base + import Lude.Haskell -import Prelude.Experimental qualified as GHC --- TODO: Generalize fst and snd (and fst1 and snd1?) with Cartesian class. --- Probably name them outl and outr for symmetry with inl and inr. +-- TODO: Generalize with Cartesian class. + +-------------------------------------------------------------------------------- + +infixl 7 * -------------------------------------------------------------------------------- type Pair :: Type -> Type -> Type -type Pair = GHC.Tuple2 +type Pair = Tuple2 -- For consistency +type MkPair :: a -> b -> Pair a b +type MkPair = (,) pattern MkPair :: a -> b -> Pair a b pattern MkPair a b = (a, b) {-# COMPLETE MkPair #-} type (*) = Pair -infixl 7 * -fst :: Pair a b -> a -fst (MkPair x _) = x +outl :: forall a b. Pair a b -> a +outl = Base.fst + +outr :: forall a b. Pair a b -> b +outr = Base.snd + +dup :: forall a. a -> Pair a a +dup x = (x, x) + +swap :: forall a b. Pair a b -> Pair b a +swap = Base.swap + +curry :: forall a b c. (Pair a b -> c) -> (a -> b -> c) +curry = Base.curry + +uncurry :: forall a b c. (a -> b -> c) -> (Pair a b -> c) +uncurry = Base.uncurry + +type Outl :: forall {a} {b}. Pair a b -> a +type family Outl _ where + Outl (a, b) = a + +type Outr :: forall {a} {b}. Pair a b -> b +type family Outr _ where + Outr (a, b) = b + +-------------------------------------------------------------------------------- +-- CPS/Yoneda Pair Operations + +-- TODO: Figure-out the best way to generalize this idea. + +type CoTuple :: forall {k} {r :: Repr}. k -> Type# r -> Type +type family CoTuple _ _ where + CoTuple () z = z -- TODO: must lift somehow + CoTuple (a) z = a -> z + CoTuple (a, b) z = a -> b -> z + CoTuple (a, b, c) z = a -> b -> c -> z + CoTuple (a, b, c, d) z = a -> b -> c -> d -> z + CoTuple (a, b, c, d, e) z = a -> b -> c -> d -> e -> z + CoTuple (a, b, c, d, e, f) z = a -> b -> c -> d -> e -> f -> z + CoTuple (a, b, c, d, e, f, g) z = a -> b -> c -> d -> e -> f -> g -> z + CoTuple (a, b, c, d, e, f, g, h) z = a -> b -> c -> d -> e -> f -> g -> h -> z + CoTuple (a, b, c, d, e, f, g, h, i) z = a -> b -> c -> d -> e -> f -> g -> h -> i -> z + CoTuple (MkTuple1 a) z = a -> z + +-- | A morphism @Tuple a -> Tuple b@ for tuples of types @a@ and @b@ with +-- arbitrary representations, without requiring `Functional#` tuples +type HomTuple :: forall {k} {l}. k -> l -> Type +type HomTuple a b = forall {r :: Repr} (z :: Type# r). CoTuple b z -> CoTuple a z + +-- | A morphism @a * b -> a' * b'@ for types @a@, @b@, @a'@, and @b'@ with +-- arbitrary representations, without requiring `Functional#` tuples +type HomPair + :: forall {r :: Repr} {s :: Repr} {r' :: Repr} {s' :: Repr} + . Type# r -> Type# s -> Type# r' -> Type# s' -> Type +type HomPair a b a' b' = HomTuple (a, b) (a', b') + +-- type HomPair a b a' b' = forall {t :: Repr} (c :: Type# t). (a' -> b' -> c) -> (a -> b -> c) + +-- | A binatural transformation @f * g ~~> f' * g'@ for type-valued functors +-- @f@, @g@, @f'@, and @g'@ with arbitrary representations, without requiring +-- `Functional#` tuples +type HomPair1 + :: forall {i} {j} {r :: Repr} {s :: Repr} {r' :: Repr} {s' :: Repr} + . (i -> Type# r) -> (j -> Type# s) -> (i -> Type# r') -> (j -> Type# s') -> Type +type HomPair1 f g f' g' = forall x y. HomPair (f x) (g y) (f' x) (g' y) + +fbimap + :: forall {r :: Repr} (a :: Type# r) {r' :: Repr} (a' :: Type# r') {s :: Repr} (b :: Type# s) {s' :: Repr} (b' :: Type# s') + . (Functional# r, Functional# r', Functional# s, Functional# s') + => (a -> a') -> (b -> b') -> HomPair a b a' b' +fbimap f g k = lam2# \x y -> app2# k (app# f x) (app# g y) -- flmap f . frmap g +{-# INLINE fbimap #-} + +flmap + :: forall {r :: Repr} (a :: Type# r) {r' :: Repr} (a' :: Type# r') {s :: Repr} (b :: Type# s) + . (Functional# r, Functional# r', Functional# s) + => (a -> a') -> HomPair a b a' b +flmap f k = lam2# \x y -> app2# k (app# f x) y -- flip (.#) +{-# INLINE flmap #-} + +frmap + :: forall {r :: Repr} (a :: Type# r) {s :: Repr} (b :: Type# s) {s' :: Repr} (b' :: Type# s') + . (Functional# r, Functional# s, Functional# s') + => (b -> b') -> HomPair a b a b' +frmap g k = lam2# \x y -> app2# k x (app# g y) -- flip (*.#) +{-# INLINE frmap #-} + +fbmap + :: forall {r :: Repr} (a :: Type# r) {r' :: Repr} (a' :: Type# r') + . (Functional# r, Functional# r') + => (a -> a') -> HomPair a a a' a' +fbmap h = fbimap h h +{-# INLINE fbmap #-} + +fbmap1 + :: forall {i} {r :: Repr} (f :: i -> Type# r) {r' :: Repr} (f' :: i -> Type# r') + . (Functional# r, Functional# r') + => (f ~> f') -> HomPair1 f f f' f' +fbmap1 h = fbimap h h +{-# INLINE fbmap1 #-} + +foutl + :: forall {r :: Repr} (a :: Type# r) {s :: Repr} (b :: Type# s) + . (Functional# r, Functional# s) => HomTuple (a, b) (a) +foutl k = lam2# \x _ -> app# k x +{-# INLINE foutl #-} -snd :: Pair a b -> b -snd (MkPair _ y) = y +foutr + :: forall {r :: Repr} (a :: Type# r) {s :: Repr} (b :: Type# s) + . (Functional# r, Functional# s) => HomTuple (a, b) (b) +foutr k = lam2# \_ y -> app# k y +{-# INLINE foutr #-} -type Fst :: forall {a} {b}. Pair a b -> a -type family Fst _ where - Fst (a, b) = a +fdup + :: forall {r :: Repr} (a :: Type# r) + . (Functional# r) => HomTuple (a) (a, a) +fdup k = lam# \x -> app2# k x x +{-# INLINE fdup #-} -type Snd :: forall {a} {b}. Pair a b -> b -type family Snd _ where - Snd (a, b) = b +fswap + :: forall {r :: Repr} (a :: Type# r) {s :: Repr} (b :: Type# s) + . (Functional# r, Functional# s) => HomPair b a a b +fswap k = lam2# \x y -> app2# k y x +{-# INLINE fswap #-}