What is this special functor structure called? - haskell

Suppose that F is an applicative functor with the additional laws (with Haskell syntax):
pure (const ()) <*> m === pure ()
pure (\a b -> (a, b)) <*> m <*> n === pure (\a b -> (b, a)) <*> n <*> m
pure (\a b -> (a, b)) <*> m <*> m === pure (\a -> (a, a)) <*> m
What is the structure called if we omit (3.)?
Where can I find more info on these laws/structures?
Comments on comments
Functors which satisfy (2.) are often called commutative.
The question is now, whether (1.) implies (2.) and how these structures can be described.
I am especially interested in structures which satisfies (1-2.) but not (3.)
Examples:
The reader monad satisfies (1-3.)
The writer monad on a commutative monoid satisfies only (2.)
The monad F given below satisfies (1-2.) but not (3.)
Definition of F:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
import Control.Monad.State
newtype X i = X Integer deriving (Eq)
newtype F i a = F (State Integer a) deriving (Monad)
new :: F i (X i)
new = F $ modify (+1) >> gets X
evalF :: (forall i . F i a) -> a
evalF (F m) = evalState m 0
We export only the types X, F, new, evalF, and the instances.
Check that the following holds:
liftM (const ()) m === return ()
liftM2 (\a b -> (a, b)) m n === liftM2 (\a b -> (b, a)) n m
On the other hand, liftM2 (,) new new cannot be replaced by liftM (\a -> (a,a)) new:
test = evalF (liftM (uncurry (==)) $ liftM2 (,) new new)
/= evalF (liftM (uncurry (==)) $ liftM (\a -> (a,a)) new)
Comments on C. A. McCann's answer
I have a sketch of proof that (1.) implies (2.)
pure (,) <*> m <*> n
=
pure (const id) <*> pure () <*> (pure (,) <*> m <*> n)
=
pure (const id) <*> (pure (const ()) <*> n) <*> (pure (,) <*> m <*> n)
=
pure (.) <*> pure (const id) <*> pure (const ()) <*> n <*> (pure (,) <*> m <*> n)
=
pure const <*> n <*> (pure (,) <*> m <*> n)
= ... =
pure (\_ a b -> (a, b)) <*> n <*> m <*> n
= see below =
pure (\b a _ -> (a, b)) <*> n <*> m <*> n
= ... =
pure (\b a -> (a, b)) <*> n <*> m
=
pure (flip (,)) <*> n <*> m
Observation
For the missing part first consider
pure (\_ _ b -> b) <*> n <*> m <*> n
= ... =
pure (\_ b -> b) <*> n <*> n
= ... =
pure (\b -> b) <*> n
= ... =
pure (\b _ -> b) <*> n <*> n
= ... =
pure (\b _ _ -> b) <*> n <*> m <*> n
Lemma
We use the following lemma:
pure f1 <*> m === pure g1 <*> m
pure f2 <*> m === pure g2 <*> m
implies
pure (\x -> (f1 x, f2 x)) m === pure (\x -> (g1 x, g2 x)) m
I could prove this lemma only indirectly.
The missing part
With this lemma and the first observation we can prove
pure (\_ a b -> (a, b)) <*> n <*> m <*> n
=
pure (\b a _ -> (a, b)) <*> n <*> m <*> n
which was the missing part.
Questions
Is this proved already somewhere (maybe in a generalized form)?
Remarks
(1.) implies (2.) but otherwise (1-3.) are independent.
To prove this, we need two more examples:
The monad G given below satisfies (3.) but not (1-2.)
The monad G' given below satisfies (2-3.) but not (1.)
Definition of G:
newtype G a = G (State Bool a) deriving (Monad)
putTrue :: G ()
putTrue = G $ put True
getBool :: G Bool
getBool = G get
evalG :: G a -> a
evalG (G m) = evalState m False
We export only the type G, putTrue, getBool, evalG, and the Monad instance.
The definition of G' is similar to the definition of G with the following differences:
We define and export execG:
execG :: G' a -> Bool
execG (G m) = execState m False
We do not export getBool.

Your first law is a very strong requirement; it implies that the functor can have no distinguished "shape" independent of the parametric portion. This rules out any functor that contains extra values (State, Writer, &c.) as well as any functor using sum types (Either, [], &c.). So this limits us to things like fixed-size containers.
Your second law requires commutativity, which means that order of nesting (that is, functor composition) doesn't matter. This might actually be implied by the first law, since we already know that the functor can't contain any information other than the parametric values, and you explicitly require preservation of that here.
Your third law requires that the functor be idempotent as well, which means that nesting something within itself using fmap is equivalent to itself. This probably implies that if the functor is a monad as well, join involves some sort of "taking the diagonal". Basically, this means that liftA2 (,) should behave like zip, not a cartesian product.
The second and third together imply that however many "primitives" the functor might have, any composition is equivalent to combining at most one of each primitive, in any order. And the first implies that if you throw out the parametric information, any combination of primitives is the same as using none at all.
In summary, I think what you have is the class of functors isomorphic to Reader. That is, functors where f a describes values of type a indexed by some other type, such as a subset of the natural numbers (for fixed-size containers) or an arbitrary type (as with Reader).
I'm not sure how to convincingly prove most of the above, unfortunately.

Related

Multiple arguments on applicatives not working?

So I'm trying to learn about monads, functors and applicatives. I've created the following renamed mirror match of Maybe called Sometimes. (I did this to learn about these things)
data Sometimes a = Nope | Thing a deriving Show
instance Monad Sometimes where
(Thing x) >>= f = f x
Nope >>= f = Nope
return = Thing
instance Applicative Sometimes where
pure = Thing
Nope <*> _ = Nope
(Thing g) <*> mx = fmap g mx
instance Functor Sometimes where
fmap _ Nope = Nope
fmap g (Thing x) = Thing (g x)
So when I do the following it works:
pure (1+) <*> (Thing 1)
> Thing 2
pure (+) <*> (Thing 1) <*> (Thing 1)
> Thing 2
But if I try three additions it doesn't work:
pure (+) <*> (Thing 1) <*> (pure 1) <*> (pure 1)
<interactive>:108:1: error:
• Non type-variable argument in the constraint: Num (a -> b)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall a b. (Num (a -> b), Num a) => Sometimes b
Why doesn't this work? I would expect the first two to be applied and then the third to be applied to the result of the first two. My book talks about how implementing fmap0, fmap1, fmap2... is inefficient and as such
... for functions with any desired number of arguments can be constructed in terms of two basic functions with the following types:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
And states further on:
A typical use of pure and <*> has the following form:
pure g <*> x1 <*> x2 <*> ... <*> xn
As such I'm expecting it to work but I'm clearly missing something in my definitions/usage of the Applicative.
I'm using the book Programming in Haskell SE by Graham Hutton
The reason this does not work is because (+) sums two numbers, not three.
You can make a function that sums three numbers, for example with:
pure (\x y z -> x+y+z) <*> (Thing 1) <*> (pure 1) <*> (pure 1)
this then gives us:
Prelude> pure (\x y z -> x+y+z) <*> (Thing 1) <*> (pure 1) <*> (pure 1)
Thing 3
Why doesn't this work? I would expect the first two to be applied and then the third to be applied to the result of the first two.
Exactly, but after the first two are applied, this is no longer a function, but a Num a => Sometimes a. Indeed, if we determines the types, we see that Thing (+) :: Num a => Sometimes (a -> a -> a) and Thing 1 :: Num b => Sometimes b, so that means that Thing (+) <*> Thing 1 has type Num a => Sometimes (a -> a).
Then we determine the type of Thing (+) <*> Thing 1 <*> Thing 1, since Thing (+) <*> Thing 1 has type Num a => Sometimes (a -> a), and the last Thing 1 has type Num c => Sometimes c, it means that Thing (+) <*> Thing 1 <*> Thing 1 has type Num a => Sometimes a, but this is not a function, unless there is a Num type that is a function, which is what the error is saying.

Is the Yoneda Lemma only useful from a theoretical point of view?

For instance, loop fusion can be obtained with Yoneda:
newtype Yoneda f a =
Yoneda (forall b. (a -> b) -> f b)
liftYo :: (Functor f) => f a -> Yoneda f a
liftYo x = Yoneda $ \f -> fmap f x
lowerYo :: (Functor f) => Yoneda f a -> f a
lowerYo (Yoneda y) = y id
instance Functor (Yoneda f) where
fmap f (Yoneda y) = Yoneda $ \g -> y (g . f)
loopFusion = lowerYo . fmap f . fmap g . liftYo
But I could have just written loopFusion = fmap (f . g). Why would I use Yoneda at all? Are there other use cases?
Well, in this case you could have done fusion by hand, because the two fmaps are "visible" in the source code, but the point is that Yoneda does the transformation at runtime. It's a dynamic thing, most useful when you don't know how many times you will need to fmap over a structure. E.g. consider lambda terms:
data Term v = Var v | App (Term v) (Term v) | Lam (Term (Maybe v))
The Maybe under Lam represents the variable bound by the abstraction; in the body of a Lam, the variable Nothing refers to the bound variable, and all variables Just v represent the ones bound in the environment. (>>=) :: Term v -> (v -> Term v') -> Term v' represents substitution—each variable can be replaced with a Term. However, when replacing a variable inside a Lam, all the variables in the produced Term need to be wrapped in Just. E.g.
Lam $ Lam $ Var $ Just $ Just $ ()
>>= \() -> App (Var "f") (Var "x")
=
Lam $ Lam $ App (Var $ Just $ Just "f") (Var $ Just $ Just "x")
The naive implementation of (>>=) goes like this:
(>>=) :: Term v -> (v -> Term v') -> Term v'
Var x >>= f = f x
App l r >>= f = App (l >>= f) (r >>= f)
Lam b >>= f = Lam (b >>= maybe (Var Nothing) (fmap Just . f))
But, written like this, every Lam that (>>=) goes under adds an fmap Just to f. If I had a Var v buried under 1000 Lams, then I would end up calling fmap Just and iterating over the new f v term 1000 times! I can't just pull your trick and fuse multiple fmaps into one, by hand, because there's only one fmap in the source code being called multiple times.
Yoneda can ease the pain:
bindTerm :: Term v -> (v -> Yoneda Term v') -> Term v'
bindTerm (Var x) f = lowerYoneda (f x)
bindTerm (App l r) f = App (bindTerm l f) (bindTerm r f)
bindTerm (Lam b) f =
Lam (bindTerm b (maybe (liftYoneda $ Var Nothing) (fmap Just . f)))
(>>=) :: Term v -> (v -> Term v') -> Term v'
t >>= f = bindTerm t (liftYoneda . f)
Now, the fmap Just is free; it's just a wonky function composition. The actual iteration over the produced Term is in the lowerYoneda, which is only called once for each Var. To reiterate: the source code nowhere contains anything of the form fmap f (fmap g x). Such forms only arise at runtime, dynamically, depending on the argument to (>>=). Yoneda can rewrite that, at runtime, to fmap (f . g) x, even though you can't rewrite it like that in the source code. Further, you can add Yoneda to existing code with minimal changes to it. (There is, however, a drawback: lowerYoneda is always called exactly once for each Var, which means e.g. Var v >>= f = fmap id (f v) where it was just f v, before.)
There is an example similar in spirit to the one described by HTNW in lens. A look at (a paraphrased version of) the lens function illustrates what a typical van Laarhoven lens looks like:
-- type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens getter setter = \f -> \s -> fmap (setter s) (f (getter s))
The occurrence of fmap in there means that composing lenses will, in principle, lead to consecutive uses of fmap. Now, most of the time this doesn't actually matter: the implementations in lens use a lot of inlining and newtype coercion so that, when using the lens combinators (view, over, and so forth), the involved functor (typically Const or Identity) is generally optimised away. In a few situations, however, it is not possible to do that (for instance, if the lens is used in such a way that a concrete choice of functor isn't done in compile time). As compensation, lens offers a helper function called fusing, which makes it possible to have fmap fusion in those special cases. Its implementation is:
-- type LensLike f s t a b = (a -> f b) -> s -> f t
fusing :: Functor f => LensLike (Yoneda f) s t a b -> LensLike f s t a b
fusing t = \f -> lowerYoneda . t (liftYoneda . f)
That being so, if you write fusing (foo . bar), Yoneda f is picked as the functor to be used by foo . bar, which guarantees fmap fusion.
(This answer was inspired by a comment by Edward Kmett, which I happened to stumble upon right before seeing this question.)

Which application is executed first?

I have following instance of Traversable:
instance Traversable (Three' a) where
traverse f (Three' x y z) = Three' x <$> f y <*> f z
the infix operator <$> and <*> has the same precedence and namely 4.
*ExercisesTraversable> :i <$>
(<$>) :: Functor f => (a -> b) -> f a -> f b
-- Defined in ‘Data.Functor’
infixl 4 <$>
*ExercisesTraversable> :i <*>
class Functor f => Applicative (f :: * -> *) where
...
(<*>) :: f (a -> b) -> f a -> f b
...
-- Defined in ‘GHC.Base’
infixl 4 <*>
Which one is going to executed first?
They don't just have precedence 4, they also have left-associativity. This is the l in infixl; one can also choose infixr for right-associativity, and infix for "throw an error if you need to know what the associativity should be". Thus
Three' x <$> f y <*> f z
is parsed as:
(Three' x <$> f y) <*> f z
As for which is executed first, that can't be answered without seeing the implementation of (<*>) that you want to ask about; Three' x <$> f y will be evaluated just far enough for (<*>) to make progress, as usual, so if (<*>) can make progress without evaluating the (<$>) call first, it will.

(r ->) applicative functor

I am having some trouble understanding how the function instance (->) r of Applicative works in Haskell.
For example if I have
(+) <$> (+3) <*> (*100) $ 5
I know you get the result 508, I sort of understand that you take the result of (5 + 3) and (5 * 100) and you apply the (+) function to both of these.
However I do not quite understand what is going on. I assume that the expression is parenthesized as follows:
((+) <$> (+3)) <*> (*100)
From my understanding what is happening is that your mapping (+) over the eventual result of (+3) and then you are using the <*> operator to apply that function to the eventual result of (*100)
However I do not understand the implementation of <*> for the (->) r instance and why I cannot write:
(+3) <*> (*100)
How does the <*>, <$> operator work when it comes to (->) r?
<$> is just another name for fmap and its definition for (->) r is (.) (the composition operator):
intance Functor ((->) r) where
fmap f g = f . g
You can basically work out the implementation for <*> just by looking at the types:
instance Applicative ((->) r) where
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
f <*> g = \x -> f x (g x)
You have a function from r to a to b and a function from r to a. You want a funtion from r to b as a result. First thing you know is you return a function:
\x ->
Now you want to apply f since it is the only item which may return a b:
\x -> f _ _
Now the arguments for f are of type r and a. r is simply x (since it alrady is of type r and you can get an a by applying g to x:
\x -> f x (g x)
Aaand you're done. Here's a link to the implementation in Haskell's Prelude.
Consider the type signature of <*>:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Compare this to the type signature for ordinary function application, $:
($) :: (a -> b) -> a -> b
Notice that they are extremely similar! Indeed, the <*> operator effectively generalizes application so that it can be overloaded based on the types involved. This is easy to see when using the simplest Applicative, Identity:
ghci> Identity (+) <*> Identity 1 <*> Identity 2
Identity 3
This can also be seen with slightly more complicated applicative functors, such as Maybe:
ghci> Just (+) <*> Just 1 <*> Just 2
Just 3
ghci> Just (+) <*> Nothing <*> Just 2
Nothing
For (->) r, the Applicative instance performs a sort of function composition, which produces a new function that accepts a sort of “context” and threads it to all of the values to produce the function and its arguments:
ghci> ((\_ -> (+)) <*> (+ 3) <*> (* 100)) 5
508
In the above example, I have only used <*>, so I’ve explicitly written out the first argument as ignoring its argument and always producing (+). However, Applicative typeclass also includes the pure function, which has the same purpose of “lifting” a pure value into an applicative functor:
ghci> (pure (+) <*> (+ 3) <*> (* 100)) 5
508
In practice, though, you will rarely see pure x <*> y because it is precisely equivalent to x <$> y by the Applicative laws, since <$> is just an infix synonym for fmap. Therefore, we have the common idiom:
ghci> ((+) <$> (+ 3) <*> (* 100)) 5
508
More generally, if you see any expression that looks like this:
f <$> a <*> b
…you can read it more or less like the ordinary function application f a b, except in the context of a particular Applicative instance’s idioms. In fact, an original formulation of Applicative proposed the idea of “idiom brackets”, which would add the following as syntactic sugar for the above expression:
(| f a b |)
However, Haskellers seem to be satisfied enough with the infix operators that the benefits of adding the additional syntax has not been deemed worth the cost, so <$> and <*> remain necessary.
Let's take a look at the types of these functions (and the definitions that we automatically get along with them):
(<$>) :: (a -> b) -> (r -> a) -> r -> b
f <$> g = \x -> f (g x)
(<*>) :: (r -> a -> b) -> (r -> a) -> r -> b
f <*> g = \x -> f x (g x)
In the first case, <$>, is really just function composition. A simpler definition would be (<$>) = (.).
The second case is a little more confusing. Our first input is a function f :: r -> a -> b, and we need to get an output of type b. We can provide x :: r as the first argument to f, but the only way we can get something of type a for the second argument is by applying g :: r -> a to x :: r.
As an interesting aside, <*> is really the S function from SKI combinatory calculus, whereas pure for (-> r) is the K :: a -> b -> a (constant) function.
As a Haskell newbie myself, i'll try to explain the best way i can
The <$> operator is the same as mapping a function on to another function.
When you do this:
(+) <$> (+3)
You are basically doing this:
fmap (+) (+3)
The above will call the Functor implementation of (->) r which is the following:
fmap f g = (\x -> f (g x))
So the result of fmap (+) (+3) is (\x -> (+) (x + 3))
Note that the result of this expression has a type of a -> (a -> a)
Which is an applicative! That is why you can pass the result of (+) <$> (+3) to the <*> operator!
Why is it an applicative you might ask? Lets look the at the <*> definition:
f (a -> b) -> f a -> f b
Notice that the first argument matches our returned function definition a -> (a -> a)
Now if we look at the <*> operator implementation, it looks like this:
f <*> g = (\x -> f x (g x))
So when we put all those pieces together, we get this:
(+) <$> (+3) <*> (+5)
(\x -> (+) (x + 3)) <*> (+5)
(\y -> (\x -> (+) (x + 3)) y (y + 5))
(\y -> (+) (y + 3) (y + 5))
The (->) e Functor and Applicative instances tend to be a bit confusing. It may help to view (->) e as an "undressed" version of Reader e.
newtype Reader e a = Reader
{ runReader :: e -> a }
The name e is supposed to suggest the word "environment". The type Reader e a should be read as "a computation that produces a value of type a given an environment of type e".
Given a computation of type Reader e a, you can modify its output:
instance Functor (Reader e) where
fmap f r = Reader $ \e -> f (runReader r e)
That is, first run the computation in the given environment, then apply the mapping function.
instance Applicative (Reader e) where
-- Produce a value without using the environment
pure a = Reader $ \ _e -> a
-- Produce a function and a value using the same environment;
-- apply the function to the value
rf <*> rx = Reader $ \e -> (runReader rf e) (runReader rx e)
You can use the usual Applicative reasoning for this as any other applicative functor.

Is there a Codensity MonadPlus that asymptotically optimizes a sequence of MonadPlus operations?

Recently there was a question about the relation between DList <-> [] versus Codensity <-> Free.
This made me think whether there is such a thing for MonadPlus. The Codensity monad improves the asymptotic performance only for the monadic operations, not for mplus.
Moreover, while there used to be Control.MonadPlus.Free, it has been removed in favor of FreeT f []. And since there is no explicit free MonadPlus, I'm not sure how one would express a corresponding improve variant. Perhaps something like
improvePlus :: Functor f => (forall m. (MonadFree f m, MonadPlus m) => m a) -> FreeT f [] a
?
Update: I attempted to create such a monad using the backtracking LogicT monad, which seems to be defined in a way similar to Codensity:
newtype LogicT r m a = LogicT { unLogicT :: forall r. (a -> m r -> m r) -> m r -> m r }
and is suited for backtracking computations, that is, MonadPlus.
Then I defined lowerLogic, similar to lowerCodensity as followd:
{-# LANGUAGE RankNTypes, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses,
UndecidableInstances, DeriveFunctor #-}
import Control.Monad
import Control.Monad.Trans.Free
import Control.Monad.Logic
lowerLogic :: (MonadPlus m) => LogicT m a -> m a
lowerLogic k = runLogicT k (\x k -> mplus (return x) k) mzero
Then, after supplementing the corresponding MonadFree instance
instance (Functor f, MonadFree f m) => MonadFree f (LogicT m) where
wrap t = LogicT (\h z -> wrap (fmap (\p -> runLogicT p h z) t))
one can define
improvePlus :: (Functor f, MonadPlus mr)
=> (forall m. (MonadFree f m, MonadPlus m) => m a)
-> FreeT f mr a
improvePlus k = lowerLogic k
However, something isn't right with it, as it seems from my initial experiments that for some examples k is distinct from improvePlus k. I'm not sure, if this is a fundamental limitation of LogicT and a different, more complex monad is needed, or just if I defined lowerLogic (or something else) wrongly.
The following is all based on my (mis)understanding of this very
interesting paper posted by Matthew Pickering in his
comment: From monoids to near-semirings: the essence of MonadPlus and
Alternative (E. Rivas, M. Jaskelioff, T. Schrijvers). All results are theirs; all mistakes are mine.
From free monoids to DList
To build up the intuition, first consider the free monoid [] over
the category of Haskell types Hask. One problem with [] is that if
you have
(xs `mappend` ys) `mappend` zs = (xs ++ ys) ++ zs
then evaluating that requires traversing and re-traversing xs for
each left-nested application of mappend.
The solution is to use CPS in the form of difference
lists:
newtype DList a = DL { unDL :: [a] -> [a] }
The paper considers the generic form of this (called the Cayley
representation) where we're not tied to the free monoid:
newtype Cayley m = Cayley{ unCayley :: Endo m }
with conversions
toCayley :: (Monoid m) => m -> Cayley m
toCayley m = Cayley $ Endo $ \m' -> m `mappend` m'
fromCayley :: (Monoid m) => Cayley m -> m
fromCayley (Cayley k) = appEndo k mempty
Two directions of generalization
We can generalize the above construction in two ways: first, by
considering monoids not over Hask, but over endofunctors of Hask;
i.e.
monads; and second, by enriching the algebraic structure into
near-semirings.
Free monads to Codensity
For any Haskell (endo)functor f, we can construct the free
monad Free f, and
it will have the analogous performance problem with left-nested binds,
with the analogous solution of using the Cayley representation
Codensity.
Near-semirings instead of just monoids
This is where the paper stops reviewing concepts that are well-known
by the working Haskell programmer, and starts homing in on its goal. A
near-semiring is like a ring, except simpler, since both addition and
multiplication are just required to be monoids. The connection between
the two operations is what you expect:
zero |*| a = zero
(a |+| b) |*| c = (a |*| c) |+| (b |*| c)
where (zero, |+|) and (one, |*|) are the two monoids over some
shared base:
class NearSemiring a where
zero :: a
(|+|) :: a -> a -> a
one :: a
(|*|) :: a -> a -> a
The free near-semiring (over Hask) turns out to be the following
Forest type:
newtype Forest a = Forest [Tree a]
data Tree a = Leaf | Node a (Forest a)
instance NearSemiring (Forest a) where
zero = Forest []
one = Forest [Leaf]
(Forest xs) |+| (Forest ys) = Forest (xs ++ ys)
(Forest xs) |*| (Forest ys) = Forest (concatMap g xs)
where
g Leaf = ys
g (Node a n) = [Node a (n |*| (Forest ys))]
(good thing we don't have commutativity or inverses,
those make free representations far from
trivial...)
Then, the paper applies the Cayley representation twice, to the two
monoidal structures.
However, if we do this naively, we do
not get a good representation: we want to represent a near-semiring,
and therefore the whole near-semiring structure must be taken into
account and not just one chosen monoid structure. [...] [W]e obtain
the semiring of endomorphisms over endomorphisms DC(N):
newtype DC n = DC{ unDC :: Endo (Endo n) }
instance (Monoid n) => NearSemiring (DC n) where
f |*| g = DC $ unDC f `mappend` unDC g
one = DC mempty
f |+| g = DC $ Endo $ \h -> appEndo (unDC f) h `mappend` h
zero = DC $ Endo $ const mempty
(I've changed the implementation here slightly from the paper to
emphasize that we are using the Endo structure twice). When we'll
generalize this, the two layers will not be the same. The paper then
goes on to say:
Note that rep is not a near-semiring homomorphism from N into DC(N)
as it does not preserve the unit [...] Nevertheless, [...] the
semantics of a computation over a near-semiring will be preserved if
we lift values to the representation, do the near-semiring computation
there, and then go back to the original near-semiring.
MonadPlus is almost a near-semiring
The paper then goes on to reformulate the MonadPlus typeclass so
that it corresponds to the near-semiring rules: (mzero, mplus) is monoidal:
m `mplus` mzero = m
mzero `mplus` m = m
m1 `mplus` (m2 `mplus` m3) = (m1 `mplus` m2) `mplus` m3
and it interacts with the monad-monoid as expected:
join mzero = mzero
join (m1 `mplus` m2) = join m1 `mplus` join m2
Or, using binds:
mzero >>= _ = mzero
(m1 `mplus` m2) >>= k = (m1 >>= k) `mplus` (m2 >>= k)
However, these are not the rules of the existing MonadPlus
typeclass from
base,
which are listed as:
mzero >>= _ = mzero
_ >> mzero = mzero
The paper calls MonadPlus instances that satisfy the
near-semiring-like laws "nondeterminism monads", and
cites Maybe as an example that is a MonadPlus but not a
nondeterminism monad, since setting m1 = Just Nothing and m2 = Just
(Just False) is a counter-example to join (m1 `mplus` m2) = join m1
`mplus` join m2.
Free and Cayley representation of nondeterminism monads
Putting everything together, on one hand we have the Forest-like
free nondeterminism monad:
newtype FreeP f x = FreeP { unFreeP :: [FFreeP f x] }
data FFreeP f x = PureP x | ConP (f (FreeP f x))
instance (Functor f) => Functor (FreeP f) where
fmap f x = x >>= return . f
instance (Functor f) => Monad (FreeP f) where
return x = FreeP $ return $ PureP x
(FreeP xs) >>= f = FreeP (xs >>= g)
where
g (PureP x) = unFreeP (f x)
g (ConP x) = return $ ConP (fmap (>>= f) x)
instance (Functor f) => MonadPlus (FreeP f) where
mzero = FreeP mzero
FreeP xs `mplus` FreeP ys = FreeP (xs `mplus` ys)
and on the other, the double-Cayley representation of the two monoidal
layers:
newtype (:^=>) f g x = Ran{ unRan :: forall y. (x -> f y) -> g y }
newtype (:*=>) f g x = Exp{ unExp :: forall y. (x -> y) -> (f y -> g y) }
instance Functor (g :^=> h) where
fmap f m = Ran $ \k -> unRan m (k . f)
instance Functor (f :*=> g) where
fmap f m = Exp $ \k -> unExp m (k . f)
newtype DCM f x = DCM {unDCM :: ((f :*=> f) :^=> (f :*=> f)) x}
instance Monad (DCM f) where
return x = DCM $ Ran ($x)
DCM (Ran m) >>= f = DCM $ Ran $ \g -> m $ \a -> unRan (unDCM (f a)) g
instance MonadPlus (DCM f) where
mzero = DCM $ Ran $ \k -> Exp (const id)
mplus m n = DCM $ Ran $ \sk -> Exp $ \f fk -> unExp (a sk) f (unExp (b sk) f fk)
where
DCM (Ran a) = m
DCM (Ran b) = n
caylize :: (Monad m) => m a -> DCM m a
caylize x = DCM $ Ran $ \g -> Exp $ \h m -> x >>= \a -> unExp (g a) h m
-- I wish I called it DMC earlier...
runDCM :: (MonadPlus m) => DCM m a -> m a
runDCM m = unExp (f $ \x -> Exp $ \h m -> return (h x) `mplus` m) id mzero
where
DCM (Ran f) = m
The paper gives the following example of a computation running in a
nondeterminism monad that will behave poorly for FreeP:
anyOf :: (MonadPlus m) => [a] -> m a
anyOf [] = mzero
anyOf (x:xs) = anyOf xs `mplus` return x
Indeed, while
length $ unFreeP (anyOf [1..100000] :: FreeP Identity Int)
takes ages, the Cayley-transformed version
length $ unFreeP (runDCM $ anyOf [1..100000] :: FreeP Identity Int)
returns instantly.

Resources