# Are these monadic expressions equivalent

I am stumbling across some short piece of monadic code and I have a question unrelated to the actual subject of the example

``````ap :: (Monad m) => m (a -> b) -> m a -> m b
ap mf mx = do
f <- mf
x <- mx
return (f x)
```

(adsbygoogle = window.adsbygoogle || []).push({});

```

remains purely symbolic, not knowing the context at all or what the code does "does" is equivalent to above

``````ap :: (Monad m) => m (a -> b) -> m a -> m b
ap mf mx = do
x <- mx
f <- mf
return (f x)
```

(adsbygoogle = window.adsbygoogle || []).push({});

```

When I first saw the example code, I was wondering if the reason why the author of this code chose the ordering f <-mf, x <-mx over x <-mx, f <- deliberately, because the order really matters or completely arbitrarily.

Regards

Gunther

+3

source to share

4 answers

No, they are not equivalent. Desugared, they

``````mf >>= (\f -> mx >>= (\x -> return (f x)))
mx >>= (\x -> mf >>= (\f -> return (f x)))
```

(adsbygoogle = window.adsbygoogle || []).push({});

```

So, the bind operation is first applied to `mf`

, and the `mx`

second in the first definition, and in the second - vice versa. The binding is not commutative, or at least it shouldn't be (it's not required by the laws of the monad). Counterexample that is not associated with IO, equal to `mf = [(+1), (+2)]`

, `mx = [1, 5]`

.

+4

source

A simple example where they are not the same (in the sense that they have different side effects):

``````mf :: IO (Int -> Int)
mf = do
putStr "Hello, "
return (+1)

mx :: IO Int
mx = do
putStr "world"
return 1

ap1 = Control.Monad.ap
ap2 mf mx = do
x <- mx
f <- mf
return (f x)
```

(adsbygoogle = window.adsbygoogle || []).push({});

```

And check it out

``````> void \$ ap1 mf mx
Hello, world
> void \$ ap2 mf mx
worldHello,
```

(adsbygoogle = window.adsbygoogle || []).push({});

```

These are obviously completely different results, although the actual calculation result is the same in both cases, i.e. 2.

+4

source

As others have pointed out, IO is a simple counterexample. The list monad is also not commutative.

``````Prelude> do f<-[succ,pred] ; x<-[10,20] ; return (f x)
[11,21,9,19]
Prelude> do x<-[10,20] ; f<-[succ,pred] ; return (f x)
[11,9,21,19]
```

(adsbygoogle = window.adsbygoogle || []).push({});

```

Let's build a short list of commutative monads.

Commutative

• Identity
• Reader /`(->) a`

• May be,
• Cont (i think?)
• [] (if you are not in order)
• Random (at least morally)
• UniqueSupply (morally at least)

Non-commutative :

• Writer
• The state
• IO / ST
• STM
• [] (if order matters)
• Or
• Random (formally)
• UniqueSupply (formally)
0

source

This question has answers on two levels:

• Are these two expressions equivalent in terms of the laws of the monad?
• Whether these two expressions are equivalent in terms of a particular monad.

To understand this, you need to: any type that instantiates `Monad`

must obey the laws of the monad, which require certain expressions to be equivalent (for example `(a >> b) >> c == a >> (b >> c)`

). But monad laws do not prohibit individual monads from having additional equivalences.

The laws of the monad by themselves do not require your two functions to be equivalent; Therefore:

• There are some specific monads where your two functions are equivalent and others where they are missing.
• If you are writing code that should work for any arbitrary monad, you may not accept equivalence.

On the other hand, multiple monads make your functions equivalent; for example `Maybe`

and `Reader`

do. A monad that obeys this equivalence is called a monastic commutative , where the order of the effects does not matter.

0

source

All Articles