Reputation: 2859
(1) Having defined two functions in the Scala REPL:
scala> def f(s: String) = "f(" + s + ")"
f: (s: String)String
scala> def g(s: String) = "g(" + s + ")"
g: (s: String)String
(2) Composing them without brackets works as expected:
scala> f _ compose g _
res18: String => String = <function1>
(3) Composing them with brackets doesn't:
scala> f(_).compose(g(_))
<console>:14: error: missing parameter type for expanded function ((x$1) => f(x$1).compose(((x$2) => g(x$2))))
f(_).compose(g(_))
^
<console>:14: error: missing parameter type for expanded function ((x$2) => g(x$2))
f(_).compose(g(_))
^
<console>:14: error: type mismatch;
found : String
required: Int
f(_).compose(g(_))
^
Question 1: Can somebody explain why?
Question 2: Why the type mismatch? Why is Scala expecting an Int
at all?
(4) Surrounding f(_)
with brackets seems to help a little bit, by making the first two errors go away:
scala> (f(_)).compose(g(_))
<console>:14: error: missing parameter type for expanded function ((x$2) => g(x$2))
(f(_)).compose(g(_))
^
Question 3: Why do these brackets help?
Question 4: Why does Scala need the parameter types, even though they are clearly defined in f
and g
respectively?
(5) Finally, adding the parameter type makes it work:
scala> (f(_)).compose(g(_:String))
res22: String => String = <function1>
Could you please explain what's going on, and provide alternative syntaxes to achieve the composition?
Thanks.
Upvotes: 0
Views: 123
Reputation: 39587
You can see the (unexpected) expansion using magic show comment:
scala> f(_).compose(g(_)) // show
[snip]
val res0 = ((x$1) => f(x$1).compose(((x$2) => g(x$2))))
Function literals need the params constrained, as you showed. f _
is eta expansion, which is different from f(_)
which is sugar for x => f(x)
.
Since the unintended application f(x$1)
returns a string, which is a Int => Char
for indexing, you get the added type mismatch.
Underscore is covered by many SO questions, including one canonical.
Upvotes: 2