Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8733111
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 13, 20262026-06-13T09:34:47+00:00 2026-06-13T09:34:47+00:00

It is well-known that applicative functors are closed under composition but monads are not.

  • 0

It is well-known that applicative functors are closed under composition but monads are not. However, I have been having trouble finding a concrete counterexample showing that monads do not always compose.

This answer gives [String -> a] as an example of a non-monad. After playing around with it for a bit, I believe it intuitively, but that answer just says “join cannot be implemented” without really giving any justification. I would like something more formal. Of course there are lots of functions with type [String -> [String -> a]] -> [String -> a]; one must show that any such function necessarily does not satisfy the monad laws.

Any example (with accompanying proof) will do; I am not necessarily looking for a proof of the above example in particular.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-13T09:34:48+00:00Added an answer on June 13, 2026 at 9:34 am

    Consider this monad which is isomorphic to the (Bool ->) monad:

    data Pair a = P a a
    
    instance Functor Pair where
      fmap f (P x y) = P (f x) (f y)
    
    instance Monad Pair where
      return x = P x x
      P a b >>= f = P x y
        where P x _ = f a
              P _ y = f b
    

    and compose it with the Maybe monad:

    newtype Bad a = B (Maybe (Pair a))
    

    I claim that Bad cannot be a monad.


    Partial proof:

    There’s only one way to define fmap that satisfies fmap id = id:

    instance Functor Bad where
        fmap f (B x) = B $ fmap (fmap f) x
    

    Recall the monad laws:

    (1) join (return x) = x 
    (2) join (fmap return x) = x
    (3) join (join x) = join (fmap join x)
    

    For the definition of return x, we have two choices: B Nothing or B (Just (P x x)). It’s clear that in order to have any hope of returning x from (1) and (2), we can’t throw away x, so we have to pick the second option.

    return' :: a -> Bad a
    return' x = B (Just (P x x))
    

    That leaves join. Since there are only a few possible inputs, we can make a case for each:

    join :: Bad (Bad a) -> Bad a
    (A) join (B Nothing) = ???
    (B) join (B (Just (P (B Nothing)          (B Nothing))))          = ???
    (C) join (B (Just (P (B (Just (P x1 x2))) (B Nothing))))          = ???
    (D) join (B (Just (P (B Nothing)          (B (Just (P x1 x2)))))) = ???
    (E) join (B (Just (P (B (Just (P x1 x2))) (B (Just (P x3 x4)))))) = ???
    

    Since the output has type Bad a, the only options are B Nothing or B (Just (P y1 y2)) where y1, y2 have to be chosen from x1 ... x4.

    In cases (A) and (B), we have no values of type a, so we’re forced to return B Nothing in both cases.

    Case (E) is determined by the (1) and (2) monad laws:

    -- apply (1) to (B (Just (P y1 y2)))
    join (return' (B (Just (P y1 y2))))
    = -- using our definition of return'
    join (B (Just (P (B (Just (P y1 y2))) (B (Just (P y1 y2))))))
    = -- from (1) this should equal
    B (Just (P y1 y2))
    

    In order to return B (Just (P y1 y2)) in case (E), this means we must pick y1 from either x1 or x3,
    and y2 from either x2 or x4.

    -- apply (2) to (B (Just (P y1 y2)))
    join (fmap return' (B (Just (P y1 y2))))
    = -- def of fmap
    join (B (Just (P (return y1) (return y2))))
    = -- def of return
    join (B (Just (P (B (Just (P y1 y1))) (B (Just (P y2 y2))))))
    = -- from (2) this should equal
    B (Just (P y1 y2))
    

    Likewise, this says that we must pick y1 from either x1 or x2, and y2 from either x3 or x4. Combining the two,
    we determine that the right hand side of (E) must be B (Just (P x1 x4)).

    So far it’s all good, but the problem comes when you try to fill in the right hand sides for (C) and (D).

    There are 5 possible right hand sides for each, and none of the combinations work. I don’t have a nice argument for this yet, but I do have a program that exhaustively tests all the combinations:

    {-# LANGUAGE ImpredicativeTypes, ScopedTypeVariables #-}
    
    import Control.Monad (guard)
    
    data Pair a = P a a
      deriving (Eq, Show)
    
    instance Functor Pair where
      fmap f (P x y) = P (f x) (f y)
    
    instance Monad Pair where
      return x = P x x
      P a b >>= f = P x y
        where P x _ = f a
              P _ y = f b
    
    newtype Bad a = B (Maybe (Pair a))
      deriving (Eq, Show)
    
    instance Functor Bad where
      fmap f (B x) = B $ fmap (fmap f) x
    
    -- The only definition that could possibly work.
    unit :: a -> Bad a
    unit x = B (Just (P x x))
    
    -- Number of possible definitions of join for this type. If this equals zero, no monad for you!
    joins :: Integer
    joins = sum $ do
      -- Try all possible ways of handling cases 3 and 4 in the definition of join below.
      let ways = [ \_ _ -> B Nothing
                 , \a b -> B (Just (P a a))
                 , \a b -> B (Just (P a b))
                 , \a b -> B (Just (P b a))
                 , \a b -> B (Just (P b b)) ] :: [forall a. a -> a -> Bad a]
      c3 :: forall a. a -> a -> Bad a <- ways
      c4 :: forall a. a -> a -> Bad a <- ways
    
      let join :: forall a. Bad (Bad a) -> Bad a
          join (B Nothing) = B Nothing -- no choice
          join (B (Just (P (B Nothing) (B Nothing)))) = B Nothing -- again, no choice
          join (B (Just (P (B (Just (P x1 x2))) (B Nothing)))) = c3 x1 x2
          join (B (Just (P (B Nothing) (B (Just (P x3 x4)))))) = c4 x3 x4
          join (B (Just (P (B (Just (P x1 x2))) (B (Just (P x3 x4)))))) = B (Just (P x1 x4)) -- derived from monad laws
    
      -- We've already learnt all we can from these two, but I decided to leave them in anyway.
      guard $ all (\x -> join (unit x) == x) bad1
      guard $ all (\x -> join (fmap unit x) == x) bad1
    
      -- This is the one that matters
      guard $ all (\x -> join (join x) == join (fmap join x)) bad3
    
      return 1 
    
    main = putStrLn $ show joins ++ " combinations work."
    
    -- Functions for making all the different forms of Bad values containing distinct Ints.
    
    bad1 :: [Bad Int]
    bad1 = map fst (bad1' 1)
    
    bad3 :: [Bad (Bad (Bad Int))]
    bad3 = map fst (bad3' 1)
    
    bad1' :: Int -> [(Bad Int, Int)]
    bad1' n = [(B Nothing, n), (B (Just (P n (n+1))), n+2)]
    
    bad2' :: Int -> [(Bad (Bad Int), Int)]
    bad2' n = (B Nothing, n) : do
      (x, n')  <- bad1' n
      (y, n'') <- bad1' n'
      return (B (Just (P x y)), n'')
    
    bad3' :: Int -> [(Bad (Bad (Bad Int)), Int)]
    bad3' n = (B Nothing, n) : do
      (x, n')  <- bad2' n
      (y, n'') <- bad2' n'
      return (B (Just (P x y)), n'')
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

It's a well known fact, that Oracle treats empty strings as null. However, I'm
I have been using the SeparatedListAdapter which is very well known and works perfectly,
It is well known that Android places our application components (Activities, Services) under threat
I have an Android application that uses the well known Strategies for Legacy Applications
It is well-known that monoids are stunningly ubiquitous in programing. They are so ubiquitous
Its a well known fact that a static method can work only on static
It's a well known problem that executing make test doesn't build the tests as
Tomcat has got that well-known memory leak problem that causes PermGen space errors after
I need a list of any well known Linux applications that uses object detection
I find that many high level functions are missing in most well-known javascript libraries

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.