# Function composition different behaviour of andThen and compose

I’m currently going through Scala with Cats and enjoying it a lot.
In Exercise 4.1.2 (Getting Func-y) we are tasked to implement `map` using the methods `pure` and `flatMap` only.

The code for reference:

``````import scala.language.higherKinds

def pure[A](a: A): F[A]

def flatMap[A, B](value: F[A])(func: A => F[B]): F[B]

def map[A, B](value: F[A])(func: A => B): F[B] =
???
}
``````

My thinking was as follows:
For the first parameter of `flatmap` we just pass `value`.
For the second parameter, we have the function `func: A => B` and a method `pure`, which, after eta expansion, has the form `pure: A => F[A]`. Therefore, we compose `pure` with `func`, i.e. we pass `pure _ compose func`, where `pure _` eta expands `pure`.

`map` would then look like this:

``````def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(pure _ compose func)
``````

However, this didn’t work and produced the following error:

``````[error] 7:35: type mismatch;
[error]   A => B|scala.Nothing
[error]     flatMap(value)(pure _ compose func)
[error]                                   ^
[info] A => B <: ? => Nothing?
[info] false
[error] 6:30: parameter value func in method map is never used
[error]   def map[A, B](value: F[A])(func: A => B): F[B] =
[error]                              ^
[error] two errors found
[error] (Compile / compileIncremental) Compilation failed
``````

To my surprise, using `func andThen pure` for the second parameter does compile.

`map` defined like this compiles:

``````def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(func andThen pure)
``````

I’m surprised because I assumed that for two functions `f: A => B` and `g: B => C`, the following would hold:

`f andThen g` is equivalent to `a => g(f(a))` and
`g compose f` is equivalent to `a => g(f(a))`,
therefore `f andThen g` and `g compose f` are equivalent.

What’s the reason that this doesn’t hold in general and in this example?

I used scala version 2.13.8 above.

I thought, maybe the problem relates to the eta expansion of the `pure` method. I found several questions relating to `compose` and `andThen` methods as well as eta expansion, but they didn’t answer my question.

I found a scala 3 reference entry about Automatic Eta Expansion, so I tried my luck in scala 3.2.1:

``````trait Monad[F[_]]:
def pure[A](a: A): F[A]

def flatMap[A, B](value: F[A])(func: A => F[B]): F[B]

def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(pure compose func)
``````

Notice, how we don’t need the underscore after `pure` anymore (it will be deprecated at some point in the future) because of the automatic eta expansion mentioned in the scala 3 reference article above.

However, this also throws an error:

``````-- [E007] Type Mismatch Error: --------------------------------------------------------
7 |    flatMap(value)(pure compose func)
|                   ^^^^^^^^^^^^^^^^^
|                   Found:    A => F[Any]
|                   Required: A => F[B]
|
|                   where:    F is a type in trait Monad with bounds <: [_] =>> Any
``````

(In the where clause, I don’t understand what kind of upper bound `[_] =>> Any` should be.)

But, again, `map` using `func andThen pure` compiles.

Based on the error message, I now believe that the compiler can somehow not infer the correct type because… of the type parameters? I don’t know.

### >Solution :

Sometimes eta-expansion is sometimes confusing for the compiler and you have to clarify things yourself.

In Scala 2 I managed to make your code compile with:

``````def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)((pure[B](_)).compose(func))
``````

because `method _` doesn’t always work and `method(_)` is more in your face (you still have to define `[B]` to avoid inferring it to something silly like `Any` or `Nothing`).

In Scala 3 it works slightly better:

``````def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)((pure[B] _).compose(func))
``````

or even

``````def map[A, B](value: F[A])(func: A => B): F[B] =
flatMap(value)(pure[B] compose func)
``````

works – you only have to provide `[B]` explicitly so that it wont attempt to combine `Nothing => F[Nothing]` with `A => B`. Currently it cannot be avoided as compiler:

• tries to infer types for `pure` before calling `compose` on eta-expanded method
• since no restriction yet applies, it infers it to `Nothing`
• only then it can infer types on `.compose` which takes `A => B` value
• however it already inferred that it should be something that is `? => Nothing`

so this particular problem comes from compiler not inferring whole expression at once but doing it in chunks.
{"ft_lang_label":"__label__en","ft_lang_prob":0.7394314,"math_prob":0.96103185,"size":4268,"snap":"2023-14-2023-23","text_gpt3_token_len":1157,"char_repetition_ratio":0.15196998,"word_repetition_ratio":0.09537167,"special_character_ratio":0.30224928,"punctuation_ratio":0.14599341,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9688549,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-03-30T05:34:35Z\",\"WARC-Record-ID\":\"<urn:uuid:d8b683ee-2ade-448d-9978-3668dbcdc6f4>\",\"Content-Length\":\"74334\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:debbc0f0-08cd-41d8-b8c2-c8e907189faf>\",\"WARC-Concurrent-To\":\"<urn:uuid:71fad9de-1f6b-46cd-87f0-5f309fef3df5>\",\"WARC-IP-Address\":\"192.0.78.211\",\"WARC-Target-URI\":\"https://devsolus.com/2023/02/15/function-composition-different-behaviour-of-andthen-and-compose/\",\"WARC-Payload-Digest\":\"sha1:GSBDEWVNPI7NZB7ZUY6BZGHKOYDZE4T6\",\"WARC-Block-Digest\":\"sha1:3PYDLEWYHOPZYORDK3T6MDVU2T7W5EY7\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-14/CC-MAIN-2023-14_segments_1679296949097.61_warc_CC-MAIN-20230330035241-20230330065241-00097.warc.gz\"}"}