nbreizh
nbreizh

Reputation: 33

Composition of partial functions to reduce code length

I want to compose a functions in a specific way to reduce code length

For instance composing a simple add function as such :


    val add3 = (a: Int, b:Int) => (c:Int) => a+b+c

    val composed = (a:Int, b:Int) => n:add3(a, b) => n(1) + n(2) + n(3)

That would be very useful so that I don't have to pass a and b as parameters every time.

Is there a way of doing that in Scala ?

Upvotes: 0

Views: 139

Answers (2)

ELinda
ELinda

Reputation: 2821

I'm also uncertain what exactly you mean, but this is how you can create a function that takes:

  • g: a function taking two or three ints, that returns an int (this would be add3 in your example)
  • f: a function taking one int, that returns an int (this would be n in your example)

and returns:

  • another function g(f), taking the same inputs as g, but first applying f
// type aliases
type TwoOrThreeIntFn = (Int, Int) => Int => Int
type OneIntFn = Int => Int

// create a function that takes two functions and returns their composition
def composition(f: OneIntFn)(g: TwoOrThreeIntFn):TwoOrThreeIntFn = { (a:Int, b:Int) => (c:Int) =>  g(f(a), f(b))(f(c)) }

Upvotes: 3

Benjamin Vialatou
Benjamin Vialatou

Reputation: 626

I'm a bit confused by these notations, like @Dima... But, I've been through this kind of ... trying to handle partial function by writing down intuitive way to... comprehend them? Is that what you're doing? So I'll try to interpret you step by step.

First, we have to be clear about add3

This code you give, maybe just as scratch to understand I guess, won't compile in scala:

val add3 = (a: Int, b:Int)(c:Int) => a+b+c

Indeed, we get in a REPL:

error: not a legal formal parameter. Note: Tuples cannot be directly destructured in method or function parameters. Either create a single parameter accepting the Tuple1, or consider a pattern matching anonymous function: `{ case (param1, param1) => ... } val add3 = (a: Int, b:Int)(c:Int) => a+b+c ^

But I may have got the idea you wanted to suggest...

add3 is either a method like:

def add3Method (a: Int, b:Int)(c:Int) = a+b+c

which can be then partially applied:

val add3 = add3Method _

Or it can directly be a function like:

val add3 = (a: Int, b:Int) => (c: Int) => a+b+c

Either way, it give a function of type (Int, Int) => Int => Int. Is that what you want?

Then we have to be clear about "composed"

This code you give, maybe just as scratch to understand I guess, won't compile in scala neither:

val composed = (a:Int, b:Int) => n:add3(a, b) => n(1) + n(2) + n(3)

But I may... Well, at least, might have got the idea you wanted to suggest too...

(a) closure?

The way you express it make me think is like a closure which would mean ultimately that composed has a type (Int, Int) => Int. Is that what you meant?

(b) a function which takes kind of a add3?

Or, you just want add3 to be just any function of the same type to pass to composed I assume is (Int, Int) => Int => Int. Is that what you meant?

Then, you have some ways to define "composed"

Either by mapping or by an intermediate variable.

closure, intermediate variable way

val composedCI = (a:Int, b:Int) => { val n = add3(a,b); n(1) + n(2) + n(3)}

closure, mapping way

val composedCM = (a:Int, b:Int) => (1 to 3).map(add3(a,b)).sum

taking as argument add3, intermediate variable way

val composedTI = (a:Int, b:Int) => (myAdd3asAnArg: (Int, Int) => Int => Int) => { val n = myAdd3asAnArg(a,b); n(1) + n(2) + n(3) }

taking as argument add3, mapping way

val composedTM = (a:Int, b:Int) => (myAdd3asAnArg: (Int, Int) => Int => Int) => (1 to 3).map(myAdd3asAnArg(a,b)).sum

Using "composed"

println(composedCM(4,5))
println(composedCI(4,5))
println(composedTM(4,5)(add3))
println(composedTI(4,5)(add3))

Will give

33
33
33
33

Hope it helps...

Upvotes: 4

Related Questions