Kevin Meredith
Kevin Meredith

Reputation: 41909

Writing Scala's Compose from scratch

When I try to write Scala's compose function, I get a compile-time error.

val compose = (a: Double => Double, b: Double => Double) = b(a)

":1: error: ';' expected but '=' found. val comp = (a: Double => Double, b: Double => Double) = b(a)"

How is this function written?

Upvotes: 1

Views: 156

Answers (3)

pedrofurla
pedrofurla

Reputation: 12783

Replace the last = with =>. The => symbol, when in a value position, separates the arguments from the function's implementation.

You declare what the function compose takes but don't declare what it returns. So I am not sure what you want. There are two possibilities here.

You may want the result of composition applied to a value, in that case it needs the value:

scala> val compose = (a: Double => Double, b: Double => Double, arg:Double) => b(a(arg))
compose: (Double => Double, Double => Double, Double) => Double = <function3>

It takes two functions, composes them and apply the arg.

You may also want the function produced by the composition of two functions:

scala> val compose = (a: Double => Double, b: Double => Double) => 
  { x:Double =>b(a(x)) }
compose: (Double => Double, Double => Double) => Double => Double = <function2>

Notice now that we have a Function2, instead of a Function3 and the return after the first set of arguments is a another function.

We could do it a bit differently:

val compose: (Double => Double, Double => Double) => Double => Double = 
  (a,b) => { x => b(a(x)) }

One of the problems here is that the usage of the => in a type position is slightly different than its usage in a value position. In a value the position, it must have argument names and the types annotation in these arguments are hints for the Scala inferrer and the return can't be declared, which the inferrer fills for us. Hence, my doubt in what you wanted.

Upvotes: 2

Randall Schulz
Randall Schulz

Reputation: 26486

You need to give the compiler more type information:

val compose: (Double => Double, Double => Double) => (Double => Double) = (a, b) => (x => b(a(x)))

scala> val dd1: Double => Double = x => x + x
dd1: Double => Double = <function1>

scala> val dd2: Double => Double = x => x * x
dd2: Double => Double = <function1>

scala> val DD1 = compose(dd1, dd2)
DD1: Double => Double = <function1>

scala> val DD2 = compose(dd2, dd1)
DD2: Double => Double = <function1>

scala> DD1(2)
res0: Double = 16.0

scala> DD2(2)
res1: Double = 8.0

Upvotes: 2

Marc Bollinger
Marc Bollinger

Reputation: 3119

Very carefully. There are two things wrong with your definition in its current state:

The first is the one that generates the exception you're seeing. You don't actually want the assignment operator preceding b(a), you want that to be the body of your anonymous function, so you'll need the => operator:

val compose = (a: Double => Double, b: Double => Double) => b(a)

However, you're still not done. In the body b(a), what the compiler thinks you're doing is applying b, with a as the parameter, so you get:

<console>:7: error: type mismatch;
 found   : Double => Double
 required: Double
     val compose = (a: Double => Double, b: Double => Double) => b(a)

As you can see, it's expecting b to take a Double, but you're passing a as an argument, which is a Double => Double / Function1[Double, Double].

So that's why you're seeing what you're seeing, and what you'd see in the next step, but I'm not entirely sure myself how to answer quite how to write compose. You can cheat somewhat by adding a parameter to compose:

scala> val compose = (a: Double => Double, b: Double => Double, c: Double) => b(a(c));
compose: (Double => Double, Double => Double, Double) => Double = <function3>

scala> compose(x => x * 2, y => y * 2, 2)
res2: Double = 8.0

But that's cheating.

Upvotes: 0

Related Questions