0

I am trying to compose these two functions:

// some case class that just holds data
case class DataMap( ... )

val action(i: Int)(data: DataMap): DataMap = { ... }

val tryFunction: DataMap => Try[DataMap] = Try.apply[DataMap]
val actionFunction: DataMap => DataMap = action(2)

tryFunction compose actionFunction

Then I get these errors:

Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `apply _` or `apply(_)` instead of `apply`.
     val tryFunction = Try.apply[DataMap]
                                ^


Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `action _` or `action(_)` instead of `action`.
     val actionFunction = action(1)
                                ^

Can someone explain why this error comes up, and how to avoid it?

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
user3685285
  • 6,066
  • 13
  • 54
  • 95
  • try `... = Try.apply[DataMap](_)` or `... = Try.apply(_: DataMap)`. – Andrey Tyukin Jul 13 '18 at 17:59
  • cool, it seems to work for now, but can you explain how this error comes about? – user3685285 Jul 13 '18 at 18:01
  • Hm, I have read a lot of those kinds of answers, but I still don't fully understand it. I'm looking for an explanation of why it is needed in my code specifically. Mine is a concrete example, so that will probably help me understand more. – user3685285 Jul 13 '18 at 18:08

1 Answers1

2

It's because of the by-name arguments of Try.apply. This here works:

import util.Try

case class DataMap()

def action(i: Int)(data: DataMap): DataMap = ???

val tryFunction: DataMap => Try[DataMap] = Try.apply[DataMap](_)
val actionFunction: DataMap => DataMap = action(2)

tryFunction compose actionFunction

The action(2) does not require eta-expansion, because the DataMap => DataMap type ascription forces the compiler to expect a function as return type, so the action(2) is converted into action(2)(_) automatically.

The Try.apply[DataMap] must be eta-converted explicitly, because the input type of apply[A] is => A (by-name) instead of just A. This is why the compiler refuses to eta-expand the method apply automatically: the types do not quite match up. If you eta-convert it explicitly, it becomes equivalent to (d: DataMap) => Try.apply[DataMap](d), so the input type is DataMap, not => DataMap.

Note that this would have worked:

val tryFunction: (=> DataMap) => Try[DataMap] = Try.apply[DataMap]

but it then wouldn't play well with the compose.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93