Functional Scala: Lambdas and other shortcuts

In the last episode, we discovered one of the most powerful concepts within the world of functional programming – Higher Order Functions. In essence, a Function is called higher ordered if it accepts another function as an argument or results into a function. This idea gives rise not only to some new ways of abstraction but also allows for pretty cool stuff like capturing or passing kind of state or building so called combinators (you may want to call them Function Makers) which will construct new functions out of some ingoing functions or some other input.

Especially talking about new forms of abstraction, we saw how to extract some use case specific, altering logic out of a function, only leaving the pure, common functionality. The specific logic was then defined within a function of its own and passed as an argument. This way we could came come up with one single function for filtering and a bunch of predicate functions, which determined how a list gets filtered in every which way. If this kind of abstraction sounds – well – to abstract, here’s the last version of our filter function again:

val  filter = ( predicate :Int => Boolean, xs :List[Int] )  =>  {
    for(  x <- xs;  if predicate( x )  )  yield x
}
...
val even =  ( x :Int ) => x % 2 == 0
val odd =  ( x :Int ) => x % 2 == 1
...
val candidates = List( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 )

val evenValues = filter( even, candidates )
val oddValues = filter( odd, candidates )

Tell me something new. We already knew that! It’s simply a higher order function beginning at line one and two predicate functions at line five and six. With those functions in the back, we can apply a list and an arbitrary predicate function to our filter function and receive a filtered list. And if we’d like to filter that list for primes, we simply define another appropriate predicate function. Now the question is, do we always have to define a predicate function first in order to pass it to our function filter? What is that for a question? Of course we need a function to pass it all way down to filter – it’s not gonna fall from heaven! Sure, sure, but you may remember the second episode about functions, where we’ve seen pure function literals:

(  x :Int,  y :Int  )  =>  x  +  y

Ahhh, remember? What we have here is simply the core of a function: the argument list followed by the function arrow and the body of the function. This one is a full fledged function, only without a given name. If you would define a function this way, there would be no way to refer to that function afterwards and hence you couldn’t call that function afterwards, because without a name it’s an anonymous one. And there we have a so called lambda expression! It’s just the pure, anonymous definition of a function.

And what’s that to do with our question? Well, even an anonymous function definition represents a value. It’s like defining any other value of any other type and don’t relate it to a name (as an alias for that value in order to refer to that value by the alias name afterwards):

val almostPi = 3.14159265                     // a value of type Double which can be referred afterwards by name almostPi

2.71828182                                    // another value of type Double, this time 'anonymous'

val mult =  ( x :Int, y :Int  )  =>  x * y    // a value of type ( Int, Int ) => Int which can by referred by name mult

(  x :Int, y :Int )  =>  x + y                // another value of type ( Int, Int ) => Int , this time again 'anonymous'

And now imagine a function which takes an argument of type Double. Just like you could call that function with an alias name which refers to a value of type Double (like double( almostPi ) ) you can of course also call that function directly with a literal of type Double (like double( 2.71828182 ) ). Yawn, that’s bussines as usual. Exactly, like it’s completely common in functional programming to pass a lambda expression directly to higher order functions! And that’s the answer to our admittedly rather rhetorical question. So that means we don’t have to introduce a predicate function necessarily with a related name before we can use it within a call to a higher order function. Instead we could define it ad hoc while calling that function:

val evenValues =  filter(  ( x :Int ) => x % 2 == 0, candidates )
...
val positiveValues = filter( ( x :Int ) => x > 0, candidates )

Ok, nice. But what can that buy us, beside from relieving us to define one-time needed functions beforehand? Well, it turns out that we can reduce the amount of ceremonial code furthermore – hooray to Scala’s type inference mechanism! If you look closely at the type of function filter, you can detect that it’s of type ( Int => Boolean, List[Int] ) => List[Int]. And you’re not the only one to detect its type. The Scala compiler is able to debunk the functions type, too! And while the compiler therefore knows the type of the predicate function, it won’t require you to document your arguments with an explicit type annotation within your function literal (since the argument types are fully determined when defining that function ad hoc during the call of a higher order function).

val evenValues =  filter(  x => x % 2 == 0,  candidates )
...
val positiveValues =  filter( x => x > 0,  candidates )

And you can get even more concise if you want to. In case you refer to every argument only once within your function body, you are allowed to completely omit the declaration of the argument list! Umm, ehmm, and how do i refer to my arguments within my functions body, then? In this case, the mythical underscore will come into operation for the first time. It’s a jack-of-all-trades (as we will see in further episodes), this time operating as a shortcut for a consecutive rererence to all arguments of the given argument list: every occurrence of the underscore within the functions body can be replaced by the value of the given argument – the first occurrence will refer to the value of the first argument, the second occurrence refers to the second argument, and so on.

val evenValues =  filter(  _ % 2 == 0,  candidates )
...
val positiveValues =  filter( _ > 0,  candidates )

In fact, this form is far too concise for some individuals! It seems like a matter of taste. But if you think in terms of readable code, it might hide too much information, for that matter (at least if you’re coming from a statically typed language like me). So as a short advice, you may apply the underscore only in a very economical way and in situations where context allows for easy recognition of the underlying types.

In fact, you’re allowed to use the underscore even within legal function definitions, as long as the compiler is able to infer the types of the given arguments. Where the following definition will provoke a compile error …

val mult  =   _ * _         // compile error : missing parameter type ...

… this slightly adapted version will compile smoothness, since we’re able to explicitly annotate the type of every argument, which is identified by each single notation of the underscore within the function body:

val mult =  ( _ :Int )  *  ( _ :Int )

In this case, the compiler has everything it needs to come up with a complete function value: there are two occurrences of the underscore, both annoteted with type Int. Hence the argument list for this function must consist of two arguments, each of type Int. Well, i’ll leave the choice up to you if this seems to be a reasonable form of function definition for you. However, there’s another compromise which may look a little more readable (at least to me) – you may declare the type of the whole expression explicitly when relating a function literal to an alias name:

val mult  : (Int, Int) => Int   =   _ * _

Ok, here the context of both underscores is nicely described within the functions type annotation. Just look at the argument list and the arrangement of both underscores shouldn’t lead to any confusion, especially if the function body is as short as in the example at hand.

Summary

This time we’ve became aquainted with a new fancy term for function literals when defined anonymously: Lambda expressions. We’ve seen their usefulness especially in situations when it’s effectual to come up with some ad hoc defined functions, which may get thrown away after usage. Now you’ve got another spacy moniker for some special form of functions in your repertoire. Beside of that, we saw how to reduce some code ceremony, using the underscore as a placeholder for function arguments. As you’ve seen, its usage might be a matter of taste, since you may loose some type information along the way. However, it’s essential that the compiler never loose track of that type information, since Scala is a statically typed language (even Scala sometimes appeared to be a dynamic typed language, when you’re allowed to omit type information). In that case we have to provide the missing type information, be it by type annotating every single occurrence of the underscore within a functions body or by an explicit type notation of the whole function expression. In either case, you should become clear to the consequences – especially in terms of readability – when leveraging those shortcuts.

Posted in Scala. 7 Comments »

7 Responses to “Functional Scala: Lambdas and other shortcuts”

  1. Tweets that mention Functional Scala: Lambdas and other shortcuts « brain driven development -- Topsy.com Says:

    […] This post was mentioned on Twitter by Richard Laksana, Alltop Agile. Alltop Agile said: brain driven development – Mario Gleichmann : Functional Scala: Lambdas and other shortcuts http://bit.ly/fqRnF1 […]

  2. World Spinner Says:

    Functional Scala: Lambdas and other shortcuts « brain driven ……

    Here at World Spinner we are debating the same thing……

  3. Functional Scala: Lambdas and other shortcuts Says:

    […] Function is called higher ordered if it accepts another function as an argument or results into… [full post] Mario Gleichmann brain driven development scala 0 0 0 0 […]

  4. Functional Scala: Turning Methods into Functions « brain driven development Says:

    […] we’ve already introduced the magical underscore as a jack-of-all-trades while discovering some shortcuts within function […]

  5. Functional Scala – Mario Gleichmann « Another Word For It Says:

    […] Functional Scala: Lambdas and other shortcuts […]

  6. Functional Scala: Curried Functions and spicy Methods « brain driven development Says:

    […] Let’s inspect how it’s going to produce that function. We can detect it as the last expression (which also becomes the return value in Scala automatically) within the body of our function maker, beginning at line 8 upto line 13.  This function only takes a single point and then starts our well known calculation. An instance (value) of that function is created whenever our function maker is called with a certain circle. And since this ad hoc created, resulting function is anonymous (look, it even lacks a name) it must be a … tataaa … lambda expression! […]

  7. cinnamon rolls Says:

    You’ve made some good points there. I checked on the web for additional information about the issue and found most people will go along with your views on this website.


Leave a reply to World Spinner Cancel reply