231

While explaining to someone what a type class X is I struggle to find good examples of data structures which are exactly X.

So, I request examples for:

  • A type constructor which is not a Functor.
  • A type constructor which is a Functor, but not Applicative.
  • A type constructor which is an Applicative, but is not a Monad.
  • A type constructor which is a Monad.

I think there are plenty examples of Monad everywhere, but a good example of Monad with some relation to previous examples could complete the picture.

I look for examples which would be similar to each other, differing only in aspects important for belonging to the particular type class.

If one could manage to sneak up an example of Arrow somewhere in this hierarchy (is it between Applicative and Monad?), that would be great too!

Rotsor
  • 13,655
  • 6
  • 43
  • 57

5 Answers5

107

A type constructor which is not a Functor:

newtype T a = T (a -> Int)

You can make a contravariant functor out of it, but not a (covariant) functor. Try writing fmap and you'll fail. Note that the contravariant functor version is reversed:

fmap      :: Functor f       => (a -> b) -> f a -> f b
contramap :: Contravariant f => (a -> b) -> f b -> f a

A type constructor which is a functor, but not Applicative:

I don't have a good example. There is Const, but ideally I'd like a concrete non-Monoid and I can't think of any. All types are basically numeric, enumerations, products, sums, or functions when you get down to it. You can see below pigworker and I disagreeing about whether Data.Void is a Monoid;

instance Monoid Data.Void where
    mempty = undefined
    mappend _ _ = undefined
    mconcat _ = undefined

Since _|_ is a legal value in Haskell, and in fact the only legal value of Data.Void, this meets the Monoid rules. I am unsure what unsafeCoerce has to do with it, because your program is no longer guaranteed not to violate Haskell semantics as soon as you use any unsafe function.

See the Haskell Wiki for an article on bottom (link) or unsafe functions (link).

I wonder if it is possible to create such a type constructor using a richer type system, such as Agda or Haskell with various extensions.

A type constructor which is an Applicative, but not a Monad:

newtype T a = T {multidimensional array of a}

You can make an Applicative out of it, with something like:

mkarray [(+10), (+100), id] <*> mkarray [1, 2]
  == mkarray [[11, 101, 1], [12, 102, 2]]

But if you make it a monad, you could get a dimension mismatch. I suspect that examples like this are rare in practice.

A type constructor which is a Monad:

[]

About Arrows:

Asking where an Arrow lies on this hierarchy is like asking what kind of shape "red" is. Note the kind mismatch:

Functor :: * -> *
Applicative :: * -> *
Monad :: * -> *

but,

Arrow :: * -> * -> *
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 3
    Good list! I would suggest using something simpler like `Either a` as an example for the last case, as it is easier to understand. – fuz Aug 28 '11 at 11:16
  • Thank you! However, I thought more like `<*>` is the 'main' function for `Applicative`. An example of a functor without `<*>` would be nice too! Or does `<*>` without `pure` not make sense? – Rotsor Aug 28 '11 at 11:20
  • @Rotsor: Hm, my wording is off. The problem is that you can implement both, but the applicative functor identities will break. I'll fix the wording. – Dietrich Epp Aug 28 '11 at 11:22
  • @Dietrich, OK, I see how `pure` is broken (it has nowhere to take a value for `Int` from), but `<*>` could work by doing intersection of the map domains. Doesn't this bring `Map Int` half-way from `Functor` to `Applicative` in some(which?) sense? – Rotsor Aug 28 '11 at 11:33
  • Wasn't there a recent post on planet.haskell.org that proved, that arrows are nothing more than applicative functors? – fuz Aug 28 '11 at 11:36
  • I suspect that Map Int has a "padding" applicative behaviour. <*> combines maps pointwise where either is defined, using the image at 0 as a default if it exists. Make pure defined only at 0 and you've got your fmap behaviour. – pigworker Aug 28 '11 at 11:49
  • @pigworker: I removed the example, I had thought that one of the applicative laws would break but on more thinking I realized I was wrong, since the applicative laws weren't symmetrical in the way I had intuited. – Dietrich Epp Aug 28 '11 at 11:57
  • One can change `Map Int` to `forall b. Map b` to make `pure` impossible. – Rotsor Aug 28 '11 at 12:05
  • @Rotsor: With such a type, `pure _ = undefined` would be a legal and correct implementation, since there are no legal values of the type anyway. – Dietrich Epp Aug 28 '11 at 12:09
  • @Rotsor: Whoops, I meant `pure _ = T empty`, because that is the only legal value. – Dietrich Epp Aug 28 '11 at 12:15
  • I meant something like `forall b. Ord b => Applicative (Map b)`, so that the values are possible, but we don't know how to create them. – Rotsor Aug 28 '11 at 12:17
  • @Rotsor: In such a case, `pure x` could simply be `T $ fromList [(0::Int,x)]`, and `<*>` could apply the leftmost element of the left operand to all of the values in the right operand, keeping the keys, so you could make a legal Applicative instance. – Dietrich Epp Aug 28 '11 at 12:48
  • @Dietrich, if you can implement Monoid for sums and products in generic way, you may want a function type to have some difficulty! :) – Rotsor Aug 28 '11 at 13:28
  • @Rotsor: Unfortunately, you can create a Monoid for any function whose result is a Monoid. – Dietrich Epp Aug 28 '11 at 13:34
  • Floating point numbers are, strictly, speaking, not genuine Monoids because they fail associativity, no? – sclv Aug 29 '11 at 19:19
  • @sclv: Anything with a finite set of values can considered to be a cyclic Monoid, whether it makes sense to do so or not. – Dietrich Epp Aug 30 '11 at 04:16
  • And of course I just realized that anything with a total ordering can be a monoid on min/max (and you can assign just about anything an arbitrary enough partial ordering) so... erp. – sclv Aug 30 '11 at 05:32
  • 7
    If you're still looking for a type constructor that's Applicative but not a Monad, a very common example would be `ZipList`. – John L Aug 05 '12 at 23:52
  • @JohnL: My new favorite example in this particular category is "parallelizeable database transactions", which are forced to be serial when made into a Monad. – Dietrich Epp Aug 06 '12 at 00:12
  • 28
    `_|_` inhabits every type in *, but the point of `Void` is you should have to bend over backwards to construct one or you've destroyed its value. This is why its not an instance of Enum, Monoid, etc. If you already have one, I'm happy to let you mash them together (giving you a `Semigroup`) but `mempty`, but I give no tools for explicitly constructing a value of type `Void` in `void`. You have to load the gun and point it at your foot and pull the trigger yourself. – Edward Kmett Dec 11 '12 at 18:44
  • 2
    Pedantically, I think your notion of Cofunctor is wrong. The dual of a functor is a functor, because you flip *both* the input *and* the output and end up with just the same thing. The notion you are looking for is probably "contravariant functor", which is slightly different. – Ben Millwood May 16 '13 at 09:55
  • @BenMillwood: I'm using "contravariant functor" as the definition for "cofunctor" because "contravariant functor" is an inconveniently long name for a type constructor. Wikipedia supports this usage. – Dietrich Epp May 16 '13 at 10:27
  • 2
    @DietrichEpp: I believe this usage to be incorrect (there's no citation), have [asked math.SE](http://math.stackexchange.com/q/394472/29966) if they agree with me. – Ben Millwood May 17 '13 at 13:28
  • Arrow fits perfectly between Applicative and Monad. Every Monad can be made into an Arrow (Kleisli Arrows) and every Arrow (with the first parameter given) is Applicative (WrappedArrow). The kind mismatch is irrelevant. – Hjulle Dec 02 '13 at 14:00
  • Hello, sorry for bringing up old question, but is there some unobvious example of basic Haskell built-in type (meaning not some esoteric one) looking like a monad but not being one? – Dan M. Jul 10 '16 at 23:49
  • @DanM.: I'm not sure what you mean by "looks like a monad", and there aren't really very many basic built-in types in Haskell (by "built-in" do you mean "in the Prelude"?) – Dietrich Epp Jul 11 '16 at 00:08
  • @DietrichEpp yeah, I mean that are standard and widely used, not your own custom one. I found ZipList, but I'm not that familiar with it (I used zip/ zipWith functions, but didn't know about it. Also Set might be a good example. – Dan M. Jul 11 '16 at 00:31
  • @DanM.: Set can't be a monad because it's not even a functor, because it imposes structure on its members. ZipList doesn't "look like" a monad to me. One of the problems here is that "looks like a monad" is a very subjective question. – Dietrich Epp Jul 11 '16 at 00:49
  • @DietrichEpp however I've seen some successful(to some degree) attempts at making Set monadic (like by using Cont monad). ALso, there is this package: https://hackage.haskell.org/package/set-monad Yeah, I guess it's kinda subjective. I was just looking for types that can be confused with monad, but in actuality are not. – Dan M. Jul 11 '16 at 01:04
  • @DietrichEpp hello, 5 years have passed and now [cofunctor is deprecated](https://hackage.haskell.org/package/cofunctor). Also, according to this [MO question](https://math.stackexchange.com/questions/394472/is-cofunctor-an-accepted-term-for-contravariant-functors), functor is self-dual, so it will be misleading to call contravariant functor cofunctor. Please update the answer, because it is so great for beginners like me! – Alex Vong Sep 17 '16 at 08:52
  • 1
    @AlexVong: "Deprecated" --> people are just using a different package. Talking about "contravariant functor" not "dual of functor", sorry for the confusion. In some contexts I've seen "cofunctor" used to refer to "contravariant functors" because functors are self-dual, but it appears to just be confusing people. – Dietrich Epp Sep 17 '16 at 16:51
  • I think that the multi-dimensional array as an example of an applicative-functor-not-a-monad is not quite correct. Why exactly is it impossible to define a monad instance for that type constructor? Below (in my answer to this question) I give specific examples of applicative functors that are either monads or not monads. In particular, a type constructor `F a` that contains a product of any number of `a`'s is always a monad. – winitzki Apr 20 '18 at 19:58
  • @winitzki: The reason it is impossible is because of the dimensions mismatch. The rank of the multidimensional array is not encoded in the type, it is encoded in the value. I don't think what you are describing is an equivalent structure. – Dietrich Epp Apr 20 '18 at 20:05
  • @winitzki: If it helps, think of `<*>` as being a tensor product, except with function application instead of multiplication. – Dietrich Epp Apr 20 '18 at 20:07
  • 1
    @DietrichEpp I don't follow what you are saying. Can you point to a specific example code for the multidimensional array? Also I don't see how it helps to look at `<*>` as tensor product. I'd rather agree that the monoidal operation `mult: F a -> F b -> F (a, b)` is similar to a tensor product. But I still don't see how this helps to verify that tensor arrays have no monad instance. – winitzki Apr 20 '18 at 22:33
  • 1
    It's not that tensors have no monad instance, it's that any monad instance couldn't be an extension of the applicative functor instance I've described. – Dietrich Epp Apr 21 '18 at 00:09
  • For any type `e` that's not pointed, `(e,-)` is a functor but not an applicative. – Student Jul 01 '20 at 12:00
  • 1
    `System.Console.GetOpt.ArgDescr` for instance is a functor, but not applicative, and cannot be made applicative (or a monoid) either, because it has multiple constructors containing its type argument. An easier example would be `data NotApplicative a = NALeft a | NARight a`. You'd have to somehow come up with a way to compose the information about if it's `NALeft` or `NARight` to get anywhere, which is possible, but I don't think there's anything you could read from the type definition alone. – CodenameLambda Jul 20 '20 at 10:56
91

My style may be cramped by my phone, but here goes.

newtype Not x = Kill {kill :: x -> Void}

cannot be a Functor. If it were, we'd have

kill (fmap (const ()) (Kill id)) () :: Void

and the Moon would be made of green cheese.

Meanwhile

newtype Dead x = Oops {oops :: Void}

is a functor

instance Functor Dead where
  fmap f (Oops corpse) = Oops corpse

but cannot be applicative, or we'd have

oops (pure ()) :: Void

and Green would be made of Moon cheese (which can actually happen, but only later in the evening).

(Extra note: Void, as in Data.Void is an empty datatype. If you try to use undefined to prove it's a Monoid, I'll use unsafeCoerce to prove that it isn't.)

Joyously,

newtype Boo x = Boo {boo :: Bool}

is applicative in many ways, e.g., as Dijkstra would have it,

instance Applicative Boo where
  pure _ = Boo True
  Boo b1 <*> Boo b2 = Boo (b1 == b2)

but it cannot be a Monad. To see why not, observe that return must be constantly Boo True or Boo False, and hence that

join . return == id

cannot possibly hold.

Oh yeah, I nearly forgot

newtype Thud x = The {only :: ()}

is a Monad. Roll your own.

Plane to catch...

Cactus
  • 27,075
  • 9
  • 69
  • 149
pigworker
  • 43,025
  • 18
  • 121
  • 214
  • I was under the impression that `Dead x` could be applicative as long as `Void` is a `Monoid`, which is certainly the case if it is a singleton... what is Void, exactly? – Dietrich Epp Aug 28 '11 at 12:17
  • 8
    Void is empty! Morally, anyhow. – pigworker Aug 28 '11 at 12:31
  • 9
    Void is a type with 0 constructors, I assume. It's not a monoid because there is no `mempty`. – Rotsor Aug 28 '11 at 12:36
  • 1
    If it has no constructors, then `pure _ = undefined` and `_ <*> _ = undefined` are legal and follow the Applicative rules. – Dietrich Epp Aug 28 '11 at 12:42
  • 2
    @Dietrich, undefined is not really a value, so this reasoning is broken. `<*>` is indeed possible, but it requires a pattern-match with 0 clauses, syntactically prohibited in Haskell, but `pure` can be called, but can not possibly return a value. – Rotsor Aug 28 '11 at 12:49
  • 7
    undefined? How rude! Sadly, unsafeCoerce (unsafeCoerce () <*> undefined) is not (), so in real life, there are observations which violate the laws. – pigworker Aug 28 '11 at 12:52
  • What? Undefined (or `_|_`) is really a value... it is the only value of type `Void`, for instance. Since `Oops` is strict, all values of type `Dead x` are therefore also `_|_`. – Dietrich Epp Aug 28 '11 at 12:59
  • 4
    @pigworker: `unsafeCoerce` has the word "unsafe" in it, which indicates that it CAN be used to violate Haskell's semantics. On the other hand, `undefined` is a well-defined part of Haskell's semantics. – Dietrich Epp Aug 28 '11 at 13:04
  • @Dietrich, this may be a valid point. It shows that Haskell does not have empty data types then. – Rotsor Aug 28 '11 at 13:18
  • 6
    In the usual semantics, which tolerates exactly one kind of undefined, you're quite right. There are other semanticses, of course. Void does not restrict to a submonoid in the total fragment. Nor is it a monoid in a semantics which distinguishes modes of failure. When I have a moment with easier than phone-based editing, I'll clarify that my example works only in a semantics for which there is not exactly one kind of undefined. – pigworker Aug 28 '11 at 15:13
  • @Dietrich Epp: Let's say that we've chosen, as Curry said, not to run away from paradoxes. `_|_` is a "value" in some senses, but obviously we can't observe it directly. However, we *can* observe aspects of a `_|_` in other ways, such as by catching exceptions in `IO`, or personally observing nontermination vs. `error`. So, as we leave the "close your eyes and pretend this is Agda" realm that calls `Void` an empty type, can you show that your proposed `Applicative` instance will obey the laws as applied to what sort of `_|_` it produces? – C. A. McCann Aug 28 '11 at 16:56
  • @C. A. McCann: Catching exceptions in the IO monad is the kind of "open secret" way to violate Haskell semantics; which is why `IO` is called "impure" even though it is monadically well-typed. You are essentially asking a function `f :: _|_ -> _|_` to preserve the precise bottom value, when, according to Haskell's denotational semantics there is only one such value in the first place. And if the Applicative laws were not written for Haskell's denotational semantics, what *were* they written for? – Dietrich Epp Aug 28 '11 at 17:11
  • @Dietrich Epp: That type doesn't make sense. `_|_` is a value, not a type, and in fact I don't believe there's even anything that says `_|_` values of different types can be compared, even conceptually. I doubt it even makes sense to consider equality of `_|_`s of the same type, so I'm not sure that satisfying type class laws is even a well-formed question in the first place without introducing something that lets you compare `_|_` values somehow. – C. A. McCann Aug 28 '11 at 17:31
  • 2
    @C. A. McCann: `_|_` in the type signature was shorthand for a type which contains only that value. (Denotational semantics are clear: there is only one `_|_`.) However, I think the root problem here is that we don't really grok how `_|_` is supposed to interact with these identities in the first place, choosing `Void` is just forcing us to deal with it. On different lines, if we decide that we cannot consider equality of `_|_`, then `newtype T a = T Void` also fails to be a Functor, in addition to failing to be Applicative. – Dietrich Epp Aug 28 '11 at 17:52
  • @Dietrich Epp: There's also only one `[]`, but asking whether empty lists of different types are equal remains nonsense; also, I'm not sure if semantic uniqueness actually justifies using `_|_` in... equivalences? Equalities? Identities? Whatever type class laws actually are, if that's even well-defined (I'm actually pretty sure they can't be identities). The `Functor` instance is far less questionable because it dodges the issue by merely preserving an existing `_|_` rather than introducing or removing `_|_` values. – C. A. McCann Aug 28 '11 at 18:13
  • 2
    @C. A. McCann: I'm not sure why you think I'm comparing values of different types. The real problem here, as I said, is we never really defined what `_|_` means in the Applicative laws. But Haskell semantics are about substitutability: I can substitute my `12` for your `12` without complaint, `_|_` should not get special treatment. And there's something especially bizarre about complaining about getting the "wrong" value of a `Void` type. – Dietrich Epp Aug 28 '11 at 18:49
  • 1
    @pigworker You claim that `unsafeCoerce (unsafeCoerce () <*> undefined)` is not `()` and hence this is a bad `Applicative` instance, but none of the `Applicative` laws seems to be of that form. (All the equations with one instance of `<*>` on some side also have `pure` on that side, according to [this list](http://en.wikibooks.org/wiki/Haskell/Applicative_Functors).) What makes you think this wacky expression ought to evaluate to `()`? – Daniel Wagner Aug 29 '11 at 04:37
  • 5
    @Dietrich Epp IMO the Applicative laws are written for the PER of total values of Haskell's denotational semantics. See [Fast and Loose Reasoning is Morally Correct](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.59.8232&rep=rep1&type=pdf). – Russell O'Connor Sep 05 '11 at 17:38
  • 2
    you can make legitimately make anything from a "value" in Void, for example, a proof of a false equation between types; of course, the only problem is that your data become mined with bottoms, so as long as crashing out or looping with bottom are not considered "going wrong", nothing will go wrong – pigworker Mar 03 '13 at 12:27
  • A recent question got me very curious about `Functor` instances that cannot be made instances of `Apply`. If you have the time, I'd love if you'd [weigh in](http://stackoverflow.com/questions/36296090/is-there-a-functor-that-cannot-be-a-law-abiding-apply). – dfeuer Mar 30 '16 at 04:05
  • 1
    Most of the silly data types used in this answer are isomorphic to real ones. For example, `Dead` is isomorphic to [`V1`](https://hackage.haskell.org/package/base-4.12.0.0/docs/GHC-Generics.html#t:V1) and `Thud` is isomorphic to [`Proxy`](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Proxy.html#t:Proxy). – Joseph Sible-Reinstate Monica Oct 20 '19 at 04:17
82

I believe the other answers missed some simple and common examples:

A type constructor which is a Functor but not an Applicative. A simple example is a pair:

instance Functor ((,) r) where
    fmap f (x,y) = (x, f y)

But there is no way how to define its Applicative instance without imposing additional restrictions on r. In particular, there is no way how to define pure :: a -> (r, a) for an arbitrary r.

A type constructor which is an Applicative, but is not a Monad. A well-known example is ZipList. (It's a newtype that wraps lists and provides different Applicative instance for them.)

fmap is defined in the usual way. But pure and <*> are defined as

pure x                    = ZipList (repeat x)
ZipList fs <*> ZipList xs = ZipList (zipWith id fs xs)

so pure creates an infinite list by repeating the given value, and <*> zips a list of functions with a list of values - applies i-th function to i-th element. (The standard <*> on [] produces all possible combinations of applying i-th function to j-th element.) But there is no sensible way how to define a monad (see this post).


How arrows fit into the functor/applicative/monad hierarchy? See Idioms are oblivious, arrows are meticulous, monads are promiscuous by Sam Lindley, Philip Wadler, Jeremy Yallop. MSFP 2008. (They call applicative functors idioms.) The abstract:

We revisit the connection between three notions of computation: Moggi's monads, Hughes's arrows and McBride and Paterson's idioms (also called applicative functors). We show that idioms are equivalent to arrows that satisfy the type isomorphism A ~> B = 1 ~> (A -> B) and that monads are equivalent to arrows that satisfy the type isomorphism A ~> B = A -> (1 ~> B). Further, idioms embed into arrows and arrows embed into monads.

Petr
  • 62,528
  • 13
  • 153
  • 317
  • 2
    So `((,) r)` is a functor that is not an applicative; but this is only because you can't generally define `pure` for all `r` at once. It's therefore a quirk of language conciseness, of trying to define an (infinite) collection of applicative functors with one definition of `pure` and `<*>`; in this sense, there doesn't seem to be anything mathematically deep about this counter-example since, for any concrete `r`, `((,) r)` *can* be made an applicative functor. Question: Can you think of a CONCRETE functor which fails to be an applicative? – George May 23 '17 at 02:30
  • 2
    See https://stackoverflow.com/questions/44125484/concrete-type-example-of-a-functor-that-fails-to-be-an-applicative as post with this question. – George May 23 '17 at 03:50
  • @George, no, it is not true. If `r` does not have any element in it, you cannot implement `pure` for that even if you can give `fmap`. – Junyoung Clare Jang Feb 14 '22 at 20:16
22

A good example for a type constructor which is not a functor is Set: You can't implement fmap :: (a -> b) -> f a -> f b, because without an additional constraint Ord b you can't construct f b.

Landei
  • 54,104
  • 13
  • 100
  • 195
  • 17
    It is actually a good example since mathematically we would *really* like to make this a functor. – Alexandre C. Oct 25 '11 at 07:02
  • 24
    @AlexandreC. I'd disagree on that, it's not a good example. Mathematically, such a data structure does form a functor. The fact that we cannot implement `fmap` is just a language/implementation issue. Also, it's possible to wrap `Set` into the continuation monad, which makes a monad out of it with all the properties we'd expect, see [this question](http://stackoverflow.com/q/12183656/1333025) (although I'm not sure if it can be done efficiently). – Petr Aug 29 '12 at 17:54
  • @PetrPudlak, how is this a language issue? Equality of `b` may be undecidable, in that case you can't define `fmap`! – Turion Apr 10 '18 at 08:47
  • @Turion Being decidable and definable are two different things. For example it's possible to correctly define equality on lambda terms (programs), even though it's not possible to decide it by an algorithm. In any case, this wasn't the case of this example. Here the problem is that we can't define a `Functor` instance with the `Ord` constraint, but it might be possible with a different definition of `Functor` or better language support. Actually with ConstraintKinds [it is possible](https://stackoverflow.com/a/31328543/1333025) to define a type class that can be parametrized like this. – Petr Apr 10 '18 at 12:06
  • Even if we could overcome the `ord` constraint the fact that a `Set` cannot contain duplicate entries means that `fmap` could altar the context. This violates the associativity law. – John F. Miller Mar 08 '19 at 20:41
17

I'd like to propose a more systematic approach to answering this question, and also to show examples that do not use any special tricks like the "bottom" values or infinite data types or anything like that.

When do type constructors fail to have type class instances?

In general, there are two reasons why a type constructor could fail to have an instance of a certain type class:

  1. Cannot implement the type signatures of the required methods from the type class.
  2. Can implement the type signatures but cannot satisfy the required laws.

Examples of the first kind are easier than those of the second kind because for the first kind, we just need to check whether one can implement a function with a given type signature, while for the second kind, we are required to prove that no implementation could possibly satisfy the laws.

Specific examples

  • A type constructor that cannot have a functor instance because the type cannot be implemented:

    data F z a = F (a -> z)
    

This is a contrafunctor, not a functor, with respect to the type parameter a, because a in a contravariant position. It is impossible to implement a function with type signature (a -> b) -> F z a -> F z b.

  • A type constructor that is not a lawful functor even though the type signature of fmap can be implemented:

    data Q a = Q(a -> Int, a)
    fmap :: (a -> b) -> Q a -> Q b
    fmap f (Q(g, x)) = Q(\_ -> g x, f x)  -- this fails the functor laws!
    

The curious aspect of this example is that we can implement fmap of the correct type even though F cannot possibly be a functor because it uses a in a contravariant position. So this implementation of fmap shown above is misleading - even though it has the correct type signature (I believe this is the only possible implementation of that type signature), the functor laws are not satisfied. For example, fmap idid, because let (Q(f,_)) = fmap id (Q(read,"123")) in f "456" is 123, but let (Q(f,_)) = id (Q(read,"123")) in f "456" is 456.

In fact, F is only a profunctor, - it is neither a functor nor a contrafunctor.

  • A lawful functor that is not applicative because the type signature of pure cannot be implemented: take the Writer monad (a, w) and remove the constraint that w should be a monoid. It is then impossible to construct a value of type (a, w) out of a.

  • A functor that is not applicative because the type signature of <*> cannot be implemented: data F a = Either (Int -> a) (String -> a).

  • A functor that is not lawful applicative even though the type class methods can be implemented:

    data P a = P ((a -> Int) -> Maybe a)
    

The type constructor P is a functor because it uses a only in covariant positions.

instance Functor P where
   fmap :: (a -> b) -> P a -> P b
   fmap fab (P pa) = P (\q -> fmap fab $ pa (q . fab))

The only possible implementation of the type signature of <*> is a function that always returns Nothing:

 (<*>) :: P (a -> b) -> P a -> P b
 (P pfab) <*> (P pa) = \_ -> Nothing  -- fails the laws!

But this implementation does not satisfy the identity law for applicative functors.

  • A functor that is Applicative but not a Monad because the type signature of bind cannot be implemented.

I do not know any such examples!

  • A functor that is Applicative but not a Monad because laws cannot be satisfied even though the type signature of bind can be implemented.

This example has generated quite a bit of discussion, so it is safe to say that proving this example correct is not easy. But several people have verified this independently by different methods. See Is `data PoE a = Empty | Pair a a` a monad? for additional discussion.

 data B a = Maybe (a, a)
   deriving Functor

 instance Applicative B where
   pure x = Just (x, x)
   b1 <*> b2 = case (b1, b2) of
     (Just (x1, y1), Just (x2, y2)) -> Just((x1, x2), (y1, y2))
     _ -> Nothing

It is somewhat cumbersome to prove that there is no lawful Monad instance. The reason for the non-monadic behavior is that there is no natural way of implementing bind when a function f :: a -> B b could return Nothing or Just for different values of a.

It is perhaps clearer to consider Maybe (a, a, a), which is also not a monad, and to try implementing join for that. One will find that there is no intuitively reasonable way of implementing join.

 join :: Maybe (Maybe (a, a, a), Maybe (a, a, a), Maybe (a, a, a)) -> Maybe (a, a, a)
 join Nothing = Nothing
 join Just (Nothing, Just (x1,x2,x3), Just (y1,y2,y3)) = ???
 join Just (Just (x1,x2,x3), Nothing, Just (y1,y2,y3)) = ???
 -- etc.

In the cases indicated by ???, it seems clear that we cannot produce Just (z1, z2, z3) in any reasonable and symmetric manner out of six different values of type a. We could certainly choose some arbitrary subset of these six values, -- for instance, always take the first nonempty Maybe - but this would not satisfy the laws of the monad. Returning Nothing will also not satisfy the laws.

  • A tree-like data structure that is not a monad even though it has associativity for bind - but fails the identity laws.

The usual tree-like monad (or "a tree with functor-shaped branches") is defined as

 data Tr f a = Leaf a | Branch (f (Tr f a))

This is a free monad over the functor f. The shape of the data is a tree where each branch point is a "functor-ful" of subtrees. The standard binary tree would be obtained with type f a = (a, a).

If we modify this data structure by making also the leaves in the shape of the functor f, we obtain what I call a "semimonad" - it has bind that satisfies the naturality and the associativity laws, but its pure method fails one of the identity laws. "Semimonads are semigroups in the category of endofunctors, what's the problem?" This is the type class Bind.

For simplicity, I define the join method instead of bind:

 data Trs f a = Leaf (f a) | Branch (f (Trs f a))
 join :: Trs f (Trs f a) -> Trs f a
 join (Leaf ftrs) = Branch ftrs
 join (Branch ftrstrs) = Branch (fmap @f join ftrstrs)

The branch grafting is standard, but the leaf grafting is non-standard and produces a Branch. This is not a problem for the associativity law but breaks one of the identity laws.

When do polynomial types have monad instances?

Neither of the functors Maybe (a, a) and Maybe (a, a, a) can be given a lawful Monad instance, although they are obviously Applicative.

These functors have no tricks - no Void or bottom anywhere, no tricky laziness/strictness, no infinite structures, and no type class constraints. The Applicative instance is completely standard. The functions return and bind can be implemented for these functors but will not satisfy the laws of the monad. In other words, these functors are not monads because a specific structure is missing (but it is not easy to understand what exactly is missing). As an example, a small change in the functor can make it into a monad: data Maybe a = Nothing | Just a is a monad. Another similar functor data P12 a = Either a (a, a) is also a monad.

Constructions for polynomial monads

In general, here are some constructions that produce lawful Monads out of polynomial types. In all these constructions, M is a monad:

  1. type M a = Either c (w, a) where w is any monoid
  2. type M a = m (Either c (w, a)) where m is any monad and w is any monoid
  3. type M a = (m1 a, m2 a) where m1 and m2 are any monads
  4. type M a = Either a (m a) where m is any monad

The first construction is WriterT w (Either c), the second construction is WriterT w (EitherT c m). The third construction is a component-wise product of monads: pure @M is defined as the component-wise product of pure @m1 and pure @m2, and join @M is defined by omitting cross-product data (e.g. m1 (m1 a, m2 a) is mapped to m1 (m1 a) by omitting the second part of the tuple):

 join :: (m1 (m1 a, m2 a), m2 (m1 a, m2 a)) -> (m1 a, m2 a)
 join (m1x, m2x) = (join @m1 (fmap fst m1x), join @m2 (fmap snd m2x))

The fourth construction is defined as

 data M m a = Either a (m a)
 instance Monad m => Monad M m where
    pure x = Left x
    join :: Either (M m a) (m (M m a)) -> M m a
    join (Left mma) = mma
    join (Right me) = Right $ join @m $ fmap @m squash me where
      squash :: M m a -> m a
      squash (Left x) = pure @m x
      squash (Right ma) = ma

I have checked that all four constructions produce lawful monads.

I conjecture that there are no other constructions for polynomial monads. For example, the functor Maybe (Either (a, a) (a, a, a, a)) is not obtained through any of these constructions and so is not monadic. However, Either (a, a) (a, a, a) is monadic because it is isomorphic to the product of three monads a, a, and Maybe a. Also, Either (a,a) (a,a,a,a) is monadic because it is isomorphic to the product of a and Either a (a, a, a).

The four constructions shown above will allow us to obtain any sum of any number of products of any number of a's, for example Either (Either (a, a) (a, a, a, a)) (a, a, a, a, a)) and so on. All such type constructors will have (at least one) Monad instance.

It remains to be seen, of course, what use cases might exist for such monads. Another issue is that the Monad instances derived via constructions 1-4 are in general not unique. For example, the type constructor type F a = Either a (a, a) can be given a Monad instance in two ways: by construction 4 using the monad (a, a), and by construction 3 using the type isomorphism Either a (a, a) = (a, Maybe a). Again, finding use cases for these implementations is not immediately obvious.

A question remains - given an arbitrary polynomial data type, how to recognize whether it has a Monad instance. I do not know how to prove that there are no other constructions for polynomial monads. I don't think any theory exists so far to answer this question.

winitzki
  • 3,179
  • 24
  • 32
  • I think `B` _is_ a monad. Can you give a counterexample to this bind `Pair x y >>= f = case (f x, f y) of (Pair x' _,Pair _ y') -> Pair x' y' ; _ -> Empty`? – Franky Apr 07 '18 at 23:12
  • @Franky Associativity fails with this definition when you choose `f` such that `f x` is `Empty` but `f y` is a `Pair`, and on the next step both are `Pair`. I checked by hand that the laws do not hold for this implementation or for any other implementation. But it's a fair bit of work to do that. I wish there were an easier way to figure this out! – winitzki Apr 08 '18 at 05:40
  • @winitzki How does associativity fail? Wouldn't you get `Empty` in either case? – melpomene Apr 09 '18 at 22:28
  • `B b1 <*> B b2 = ...` makes no sense, since `B` is not a value constructor. Also, I think `Pair (x1, x2) (y1, y2)` has the wrong type, should that be `Pair (x1 x2) (y1 y2)` ? – chi Apr 09 '18 at 22:32
  • Yes you are right @chi - my Haskell syntax is rusty. – winitzki Apr 10 '18 at 02:22
  • Just to clarify: In `Either a (m a)`, did you intend to have `a` twice? If so, it might bear some explanation -- I don't think that monad former is one of the ones well-known to Haskell folks. If not, then the first case of `type L a = Either c (w, a)` is completely subsumed by the second case, since `(w, a)` is the writer monad. – Daniel Wagner Apr 10 '18 at 02:35
  • @DanielWagner Yes, it is specifically intended to have `a` twice. This is a nontrivial construction. – winitzki Apr 10 '18 at 04:21
  • How do you really prove that there is no `Monad` instance? Your argument "there is no natural way of implementing `bind` when a function `f :: a -> B b` could return `Empty` or `Pair` for different values of `a`" works for `Maybe` as well. – Turion Apr 10 '18 at 08:46
  • 1
    @Turion That argument doesn't apply to `Maybe` because `Maybe` doesn't contain different values of `a` to worry about. – Daniel Wagner Apr 10 '18 at 10:36
  • 1
    @Turion I proved this by a couple of pages of calculations; the argument about "natural way" is just a heuristic explanation. A `Monad` instance consists of functions `return` and `bind` that satisfy laws. There are two implementations of `return` and 25 implementations of `bind` that fit the required types. You can show by direct calculation that none of the implementations satisfy the laws. To cut down on the amount of required work, I used `join` instead of `bind` and used the identity laws first. But it's been a fair bit of work. – winitzki Apr 10 '18 at 16:22
  • @melpomene I looked back at my calculations and you are right, - it is not associativity that fails in this case, it is one of the identity laws. – winitzki Apr 10 '18 at 16:48
  • The accepted answer to this question, https://stackoverflow.com/questions/13034229/concrete-example-showing-that-monads-are-not-closed-under-composition-with-proo?rq=1, claims that `Maybe (a, a)` is not a monad, and gives a partial proof. I have a complete proof but it's long. – winitzki Apr 10 '18 at 20:26
  • From a comment in that question: _So, in short: monads are allowed to throw away information, and that's okay if they're just nested in themselves. But when you have an info-preserving monad and an info-dropping monad, combining the two drops information, even though the info-preserving one needs that info kept to satisfy its own monad laws. So you can't combine arbitrary monads. (This is why you need Traversable monads, which guarantee they won't drop relevant information; they're arbitrarily composable.)_ Correction: composing works only in one way: `(Maybe a, Maybe a)` is a monad. – winitzki Apr 10 '18 at 20:29
  • A question with counter examples where the monad fails can be found here: https://stackoverflow.com/questions/49742377/is-data-poe-a-empty-pair-a-a-a-monad – Franky Apr 10 '18 at 20:35
  • A very interesting answer. A quick parenthetical question: does your `Either a (m a)` instance needs `Traversable m`? I'd suppose so, as if you were writing `join` it seems you'd need to change `m (Either a (m a))` into `Either a (m (m a))`. (That doesn't qualify as an objection to your instance, as all polynomial functors are `Traversable`.) – duplode Apr 11 '18 at 14:17
  • 1
    @duplode No, I don't think `Traversable` is needed. `m (Either a (m a))` is transformed using `pure @m` into `m (Either (m a) (m a))`. Then trivially `Either (m a) (m a) -> m a`, and we can use `join @m`. That was the implementation for which I checked the laws. – winitzki Apr 11 '18 at 17:15
  • @winitzki Oh, nice! That had escaped me somehow. (I still have to check if instance using `Traversable` is lawful. I guess it isn't -- not for all `m`, at least.) – duplode Apr 12 '18 at 01:10
  • Though you have already realised that (cf. [this comment of yours in the other question](https://stackoverflow.com/questions/49742377/is-data-poe-a-empty-pair-a-a-a-monad#comment86542732_49742377)), you might want to update this answer to account for `Either (a,a) (a,a,a,a)` actually being a monad -- it is isomorphic to `(a, Either a (a,a,a))`. – duplode Apr 15 '18 at 05:10
  • @duplode Yes, thank you - I have updated the answer. Actually, a `Monad` instance can be defined for any sum of any number of product of any number of `a`s, and possibly in more than one way. The practical usefulness of any of these monads remains to be determined. For example, what could be a use case for something like `Either (a, a, a) (a, a, a, a, a)`? – winitzki Apr 17 '18 at 19:20
  • @winitzki "[...] possibly in more than one way" -- Yup, it's a beautiful mess. `Either a (a, a)` has the two instances described [here](https://stackoverflow.com/a/43685083), which correspond to (warning: abuse of notation) `a + a^2` and `a * (1 + a)`. If you upgrade it to `One a | Two a a | Three a a a`, you get two instances by factoring it as either `a + (a * (a + a^2))` or `a + (a^2 * (1 + a))` -- they are subtly different, in a way I can't quite explain in words. Clarifying how emptiness (as in `Maybe (a, a)` / `1 + a^2`) gets in the way might help making sense of it all. – duplode Apr 20 '18 at 04:17
  • @duplode Thank you, I reorganized and edited my answer with your example in mind. – winitzki May 03 '18 at 00:15
  • @winitzki This expanded answer is really nice. By the way, I should review my own answer about diagonals in the other question -- it feels a little coarse after this discussion. – duplode May 03 '18 at 13:40
  • The claim that a type-correct `fmap` for `data F a = F (a -> Int)` can't be written is false: `fmap _ _ = F (\_ -> 0)`. The only problem with it is that it's unlawful. – Joseph Sible-Reinstate Monica Nov 10 '19 at 05:13
  • @JosephSible Thank you, I corrected the text. The example should be correct now. (a -> z instead of a -> Int) – winitzki Nov 17 '19 at 20:49
  • Today I read the original [Applicative programming with effects](https://www.cambridge.org/core/services/aop-cambridge-core/content/view/C80616ACD5687ABDC86D2B341E83D298/S0956796807006326a.pdf/applicative-programming-with-effects.pdf) paper. It contains an example of `A functor that is Applicative but not a Monad because the type signature of bind can't be implemented.`: `newtype Accy o a = Acc{acc :: o }` contains the phantom type `a`. As such, `(>>=) :: Accy o a → (a → Accy o b) → Accy o b` cannot be implemented because there is no way to ever construct an `a`. – Qqwy Jul 15 '22 at 19:21
  • 1
    @Qqwy Yes, this is a good example. It corresponds to a constant functor (that does not depend on its type parameter). Constant functors are monads only when they are of type Unit. – winitzki Jul 17 '22 at 07:15