External Publication
Visit Post

Improving `memory` with better abstractions

Haskell Community [Unofficial] February 21, 2026
Source

Indeed - over each does grant pointwise access, but the proposed Endofunctor class has different implications that the optics may not cover - same shape, different intent / use. I mostly intend it for internal use as machinery for defining different unit types that have associated algebras, so it is not necessarily meant for external use, like Data.ByteString.Internal.

As a relevant example of what I mean by same shape different use: lattices vs logics vs boolean algebras where technically they are all defined by the same five functions:

-- Actually a bounded distributive complementary lattice but who's counting
class (Eq a) => Lattice a where
    meet :: a -> a -> a
    top :: a
    join :: a -> a -> a
    bottom :: a
    complement :: a -> a

class (Eq a) => Logical a where
    conjunction :: a -> a -> a
    tautology :: a
    disjunction :: a -> a -> a
    contradiction :: a
    negation :: a -> a

-- *Pointwise* boolean eg hence 'ones' instead of 'one' or 'true'
-- Dont worry about it :)
class (Eq a) => Boolean a where
    and :: a -> a -> a
    ones :: a
    or :: a -> a -> a
    zeroes :: a
    not :: a -> a

So you can see meet = conjunction = and, and so on, and we could choose any one of the three as the root to implement the others, but lattices are about order, logics allow for short circuiting, and pointwise algebras can efficiently be performed in parallel - same shape, different uses - and our endofunctor class is actually pretty concerned with that last one.

In particular, I’d actually like to be able to define a stricter subclass / constrain Endofunctor further, something more along the lines of this, which emphasizes that it is a pointwise algebra eg pointwise @Boolean @Bit complement bytes:

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableSuperClasses #-}

class (k u, k mu) => Pointwise (k :: Type -> Constraint) u mu where
    pointwise :: (u -> u) -> mu -> mu
    zipPointwise :: (u -> u -> u) -> mu -> mu -> mu

-- Trivially, every instance of an algebra is pointwise over itself
instance (k a) => Pointwise k a a where
    pointwise = id
    zipPointwise = id

It more strongly implies the link between algebra u and algebra mu, which goes further than just granting access to the subunits. Despite not actually constraining the function argument of pointwise to the algebra in question, partial type applications such as pointwise @Boolean do constrain the types, and we might find cases where we can SPECIALIZE pointwise f = f to eg to skip the individual pointwise mapping with a more efficient implementation when available, if that is possible like list fusion!

However an actual Pointwise class is overkill and I’m not sure GHC can actually enforce this sort of specialization because eg type checking may fail to complete PLUS a lot of the time can just call op mu directly instead of pointwise op mu if you know what type mu is.

Discussion in the ATmosphere

Loading comments...