Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compose and andThen methods

Tags:

scala

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?

like image 243
lowercase Avatar asked Sep 21 '11 19:09

lowercase


People also ask

What is andThen () in Java?

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.

What is andThen in Scala?

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))

What does function identity () do?

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.

What is BiFunction in Java?

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.


2 Answers

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.

like image 88
Daniel C. Sobral Avatar answered Sep 19 '22 18:09

Daniel C. Sobral


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.

like image 43
agilesteel Avatar answered Sep 19 '22 18:09

agilesteel