[Haskell-cafe] A quick question about distribution of finite maps.

Olaf Klinke olf at aatal-apotheke.de
Sun Jan 10 07:16:38 UTC 2021


On Sat, 2021-01-09 at 18:04 -0500, David Feuer wrote:
> `These` is not my own invention. It's in the `these` package.

Then please interpret my "due to David Feuer" as "brought into this
discussion by David Feuer". I wonder whether These has ever been linked
to categorical products in Kleisli Maybe before. There are
Data.These.Combinators.justHere and justThere which are the same as my
fstMaybe and sndMaybe. But combinators resulting in pairKleisli and
iso1 seem to be missing from the these package. 

Olaf

> 
> On Sat, Jan 9, 2021, 5:41 PM Olaf Klinke <olf at aatal-apotheke.de>
> wrote:
> 
> > On Sat, 2021-01-09 at 22:26 +0100, MigMit wrote:
> > > Actually, it's pretty easy to construct a type `P x y`, so that
> > > Maybe
> > > (P x y) ~ (Maybe x, Maybe y). It would be
> > > 
> > > data OneOrBoth x y = Left' x | Right' y | Both x y
> > > 
> > > The isomorphism is, I think, obvious
> > > 
> > > iso1 :: Maybe (OneOrBoth x y) -> (Maybe x, Maybe y)
> > > iso1 Nothing = (Nothing, Nothing)
> > > iso1 (Just (Left' x)) = (Just x, Nothing)
> > > iso1 (Just (Right' y)) = (Nothing, Just y)
> > > iso1 (Just (Both x y)) = (Just x, Just y)
> > > 
> > > iso2 :: (Maybe x, Maybe y) -> Maybe (OneOrBoth x y)
> > > iso2 = -- left as an excersize for the reader
> > > 
> > > And indeed, "OneOrBoth" would be a cartesian product functor in
> > > the
> > > category of finite types (and maps).
> > 
> > I stand corrected. Below is the full code, in case anyone wants to
> > play
> > with it.
> > 
> > import Control.Arrow ((&&&))
> > 
> > -- due to David Feuer
> > data OneOrBoth x y = Left' x | Right' y | Both x y
> > 
> > iso2 :: (Maybe x,Maybe y) -> Maybe (OneOrBoth x y)
> > iso2 p = case p of
> >     (Nothing,Nothing) -> Nothing
> >     (Just x,Nothing) -> (Just (Left' x))
> >     (Nothing,Just y) -> (Just (Right' y))
> >     (Just x, Just y) -> (Just (Both x y))
> > 
> > -- (OneOrBoth x) is a functor on Kleisli Maybe
> > fmapKleisli :: (a -> Maybe b) ->
> >     OneOrBoth x a -> Maybe (OneOrBoth x b)
> > fmapKleisli k (Left' x) = Just (Left' x)
> > fmapKleisli k (Right' a) = fmap Right' (k a)
> > fmapKleisli k (Both x a) = fmap (Both x) (k a)
> > 
> > -- is OneOrBoth the cartesian product? Seems so:
> > 
> > pairKleisli :: (a -> Maybe x) ->
> >     (a -> Maybe y) ->
> >     a -> Maybe (OneOrBoth x y)
> > pairKleisli f g = iso2 . (f &&& g)
> > 
> > fstMaybe :: OneOrBoth x y -> Maybe x
> > fstMaybe (Left' x) = Just x
> > fstMaybe (Both x _) = Just x
> > fstMaybe (Right' _) = Nothing
> > 
> > sndMaybe :: OneOrBoth x y -> Maybe y
> > sndMaybe (Left' _) = Nothing
> > sndMaybe (Right' y) = Just y
> > sndMaybe (Both _ y) = Just y
> > 
> > > But it won't be cartesian closed. If it were, then for any finite
> > > X
> > > and Y we should have
> > > 
> > > Maybe (X^Y) ~
> > > () -> Maybe (X^Y) ~
> > > OneOrBoth () Y -> Maybe X ~
> > > (() -> Maybe X, Y -> Maybe X, ((), Y) -> Maybe X) ~
> > > (Maybe X, Y -> Maybe X, Y -> Maybe X)
> > > 
> > > so
> > > 
> > > X^Y ~ (X, Y -> Maybe X, Y -> Maybe X)
> > > 
> > > But then
> > > 
> > > Z -> Maybe (X^Y) ~
> > > Z -> (Maybe X, Y -> Maybe X, Y -> Maybe X) ~
> > > (Z -> Maybe X, (Z, Y) -> Maybe X, (Z, Y) -> Maybe X) ~
> > > 
> > > and
> > > 
> > > OneOrBoth Z Y -> Maybe X ~
> > > (Z -> Maybe X, Y -> Maybe X, (Z, Y) -> Maybe X)
> > > 
> > > We see that those aren't the same, they have a different number
> > > of
> > > elements, so, no luck.
> > 
> > Doesn't this chain of isomorphisms require () to be the terminal
> > object, or did you take () as synonym for the terminal object in
> > the
> > category? For example, there are several functions of the type
> > Bool -> Maybe ().
> > So the terminal object in Kleisli Maybe would be Void, because
> > Maybe
> > Void ~ (). We'd need to make fields in OneOrBoth strict to have an
> > isomorphism OneOrBoth Void a ~ a, just as the true categorical
> > product
> > in (->) is the strict pair.
> > 
> > Olaf
> > 
> > > > On 9 Jan 2021, at 22:01, Olaf Klinke <olf at aatal-apotheke.de>
> > > > wrote:
> > > > 
> > > > > Hello!
> > > > > 
> > > > > Finite maps from `"containers" Data.Map` look like they may
> > > > > form
> > > > > a
> > > > > Cartesian closed category. So it makes sense to ask if the
> > > > > rule
> > > > > _α ⇸
> > > > > (β ⇸ γ) ≡ ⟨α; β⟩ ⇸ γ ≡ ⟨β; α⟩ ⇸ γ ≡ β ⇸ (α ⇸ γ)_ that holds
> > > > > in
> > > > > such
> > > > > categories does hold for finite maps. Note that, a map being
> > > > > a
> > > > > functor, this also may be seen as _f (g α) ≡ g (f α)_, which
> > > > > would
> > > > > work if maps were `Distributive` [1].
> > > > > 
> > > > > It looks to me as though the following definition might work:
> > > > > 
> > > > >    distribute = unionsWith union . mapWithKey (fmap .
> > > > > singleton)
> > > > > 
> > > > > — And it works on simple examples. _(I checked the law
> > > > > `distribute ∘
> > > > > distribute ≡ id` — it appears to be the only law required.)_
> > > > > 
> > > > > Is this definition correct? Is it already known and defined
> > > > > elsewhere?
> > > > > 
> > > > > [1]:
> > > > > 
> > https://hackage.haskell.org/package/distributive-0.6.2.1/docs/Data-Distributive.html#t:Distributive
> > > > Hi Ignat,
> > > > 
> > > > TL;DR: No and no.
> > > > 
> > > > The documentation says that every distributive functor is of
> > > > the
> > > > form
> > > > (->) x for some x, and (Map a) is not like this.
> > > > 
> > > > If Maps were a category, what is the identity morphism?
> > > > 
> > > > Let's put the Ord constraint on the keys aside, Tom Smeding has
> > > > already
> > > > commented on that. Next, a Map is always finite, hence let's
> > > > pretend
> > > > that we are working inside the category of finite types and
> > > > functions.
> > > > Then the problems of missing identity and missing Ord go away.
> > > > Once
> > > > that all types are finite, we can assume an enumerator. That
> > > > is,
> > > > each
> > > > type x has an operation
> > > > enumerate :: [x]
> > > > which we will use to construct the inverse of
> > > > flip Map.lookup :: Map a b -> a -> Maybe b
> > > > thereby showing that a Map is nothing but a memoized version of
> > > > a
> > > > Kleisli map (a -> Maybe b). Convince yourself that Map
> > > > concatenation
> > > > has the same semantics as Kleisli composition (<=<). Given a
> > > > Kleisli
> > > > map k between finite types, we build a Map as follows.
> > > > \k -> Map.fromList (enumerate >>= (\a -> maybe [] (pure.(,) a)
> > > > (k
> > > > a)))
> > > > 
> > > > With that knowledge, we can answer your question by deciding:
> > > > Is
> > > > the
> > > > Kleisli category of the Maybe monad on finite types Cartesian
> > > > closed?
> > > > Short answer: It is not even Cartesian.
> > > > There is an adjunction between the categories (->) and (Kleisli
> > > > m)
> > > > for
> > > > every monad m, where
> > > > * The left adjoint functor takes
> > > >   types x to x,
> > > >   functions f to return.f
> > > > * The right adjoint functor takes
> > > >   types x to m x,
> > > >   Kleisli maps f to (=<<) f
> > > > Right adjoint functors preserve all existing limits, which
> > > > includes
> > > > products. Therefore, if (Kleisli m) has binary products, then m
> > > > must
> > > > preserve them. So if P x y was the product of x and y in
> > > > Kleisli m,
> > > > then m (P x y) would be isomorphic to (m x,m y). This seems not
> > > > to
> > > > hold
> > > > for m = Maybe: I can not imagine a type constructor P where
> > > > Maybe (P x y) ~ (Maybe x,Maybe y).
> > > > In particular, P can not be (,). The only sensible Kleisli
> > > > projections
> > > > from (x,y) would be fst' = return.fst and snd' = return.snd.
> > > > Now
> > > > think
> > > > of two Kleisli maps f :: Bool -> Maybe x, g :: Bool -> Maybe y.
> > > > Assume
> > > > that f True = Just x for some x and g True = Nothing. In order
> > > > to
> > > > satisfy g True = (snd' <=< (f&&&g))True, the unique pair arrow
> > > > (f&&&g)
> > > > would need to map True to Nothing, but then f True = (fst' <=<
> > > > (f&&&g))
> > > > True can not hold. We conclude that (Kleisli Maybe) does not
> > > > even
> > > > have
> > > > categorical products, so asking for Cartesian closure does not
> > > > make
> > > > sense.
> > > > 
> > > > You might ask for a weaker property: For every type x, ((,) x)
> > > > is a
> > > > functor on (Kleisli Maybe). Indeed, the following works because
> > > > ((,) x)
> > > > is a polynomial functor.
> > > > fmapKleisli :: Functor m => (a -> m b) -> (x,a) -> m (x,b)
> > > > fmapKleisli f (x,a) = fmap ((,) x) (f a)
> > > > Thus you may ask whether this functor has a right adjoint in
> > > > the
> > > > Kleisli category of Maybe. This would be a type constructor g
> > > > with
> > > > a
> > > > natural isomorphism
> > > > 
> > > > (x,a) -> Maybe b   ~   a -> Maybe (g b).
> > > > 
> > > > The first thing that comes to mind is to try
> > > > g b = x -> Maybe b and indeed djinn can provide two functions
> > > > going
> > > > back and forth that have the right type, but they do not
> > > > establish
> > > > an
> > > > isomorphism. I doubt there is such a right adjoint g, but can
> > > > not
> > > > prove
> > > > it at the moment. The idea is that a function (x,a) -> Maybe b
> > > > may
> > > > decide for Nothing depending on both x and a, and therefore the
> > > > image
> > > > function under the isomorphism must map every a to Just (g b)
> > > > and
> > > > delay
> > > > the Nothing-decision to the g b. But for the reverse
> > > > isomorphism
> > > > you
> > > > can have functions that do not always return Just (g b) and
> > > > there
> > > > is no
> > > > preimage for these.
> > > > 
> > > > Regards,
> > > > Olaf
> > > > 
> > > > 
> > > > 
> > > > _______________________________________________
> > > > Haskell-Cafe mailing list
> > > > To (un)subscribe, modify options or view archives go to:
> > > > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> > > > Only members subscribed via the mailman list are allowed to
> > > > post.



More information about the Haskell-Cafe mailing list