Function implicit parameters not any more so after passing it to a higher order function
Asked Answered
L

2

8

In Scala you can do things like:

def foo(implicit v: Int) = println(v);
def h(x: Int) = { implicit val i: Int = x; foo }

h(42)
> 42

h call gets foo reference as a closure.

It wouldn't be strange to try passing foo to h as a parameter:

def g(x: Int)(f: Int => Unit) = { implicit val i: Int = x; f }

But it wouldn't work:

g(1)(foo)
> error: could not find implicit value for parameter v: Int

What I think it's happening is that foo gets called as an evaluation of the actual parameter. Is that right?

When passed a function with a normal parameter list (not implicit), the function is not being evaluated:

def foo2(v: Int) = println("Foo2")
g(1)(foo2)
> Int => Unit = <function1>

This is an expected result and foo2 evaluation is not tried as a evaluation of an actual parameter.

Why is foo evaluated as an actual parameter when no implicit values are available to do so?

Same occurs with assignation:

val fooref: Int => Unit = foo
> error: could not find implicit value for parameter v: Int

It is like since Int => Unit doesn't match with a function where the Int parameter is marked as implicit, the compiler discard it as a valid actual parameter and therefore tries to evaluate it. Not finding a declared implicit value to fulfill the call.

If that is the case, what whould be the way of expressing the type of a function with implicit parameters?

Liebman answered 22/9, 2015 at 12:20 Comment(0)
D
12

Unfortunately, functions cannot have implicit parameters - only methods can.

In the expression g(1)(foo), foo is converted from a method to a function (also known as eta-expansion). And section 6.26.2 of the Scala Specification states that implicit arguments are applied before eta-expansion.

See this ticket: implicit methods behave suboptimally when used non-implicitly

Dardani answered 22/9, 2015 at 12:42 Comment(0)
D
1

The type of the f parameter to function g is Function1[Int, Unit]. Function1[A, B] is a trait with the single method apply(a: A): B, where the a is not implicit. Hence, you cannot create an instance of Function1[Int, Unit] from foo - it wouldn't have the right signature.

Dominion answered 22/9, 2015 at 12:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.