I'm following the tutorial Pattern matching & functional composition on Scala compose
and andThen
methods. There's such an example:
scala> def addUmm(x: String) = x + " umm" scala> def addAhem(x: String) = x + " ahem" val ummThenAhem = addAhem(_).compose(addUmm(_))
When I try to use it I get an error:
<console>:7: error: missing parameter type for expanded function ((x$1) => addAhem(x$1).compose(((x$2) => addUmm(x$2)))) val ummThenAhem = addAhem(_).compose(addUmm(_)) ^ <console>:7: error: missing parameter type for expanded function ((x$2) => addUmm(x$2)) val ummThenAhem = addAhem(_).compose(addUmm(_)) ^ <console>:7: error: type mismatch; found : java.lang.String required: Int val ummThenAhem = addAhem(_).compose(addUmm(_))
However, this works:
val ummThenAhem = addAhem _ compose addUmm _
or even
val ummThenAhem = addAhem _ compose addUmm
What's wrong with the code in the tutorial? Isn't the latter expression the same as the first one without parenthesis?
Java's . compose() and . andThen() are just the Java equivalent of this. Use the one that makes the code seem easiest to you. In terms of performance there is no significant difference.
andThen is just function composition. Given a function f val f: String => Int = s => s.length. andThen creates a new function which applies f followed by the argument function val g: Int => Int = i => i * 2 val h = f.andThen(g) h(x) is then g(f(x))
identity(). The identity function in math is one in which the output of the function is equal to its input. In Java, Function is a functional interface whose identity method returns a Function that always returns its input arguments.
Interface BiFunction<T,U,R> Represents a function that accepts two arguments and produces a result. This is the two-arity specialization of Function . This is a functional interface whose functional method is apply(Object, Object) . Since: 1.8 See Also: Function.
Well, this:
addUhum _
is an eta expansion. It converts methods into functions. On the other hand, this:
addUhum(_)
is an anonymous function. In fact, it is a partial function application, in that this parameter is not applied, and the whole thing converted into a function. It expands to:
x => addUhum(x)
The exact rules for expansion are a bit difficult to explain, but, basically, the function will "start" at the innermost expression delimiter. The exception is partial function applications, where the "x" is moved outside the function -- if _
is used in place of a parameter.
Anyway, this is how it expands:
val ummThenAhem = x => addAhem(x).compose(y => addUmm(y))
Alas, the type inferencer doesn't know the type of x or y. If you wish, you can see exactly what it tried using the parameter -Ytyper-debug
.
addAhem
is a method. compose
method is defined on functions. addAhem _
converts addAhem
from method to function, so compose
can be called on it. compose
expects a function as it's argument. You are giving it a method addUmm
by converting addUmm
into a function with addUmm _
(The underscore can be left out because the compiler can automatically convert a method into a function when it knows that a function is expected anyway). So your code:
addAhem _ compose addUmm
is the same as
(addAhem _).compose(addUmm)
but not
addAhem(_).compose(addUmm(_))
PS I didn't look at the link you provided.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With