Scala: read “from outside in” instead of “inside o

2019-08-10 11:17发布

问题:

I have something that looks like this:

def a(b:String)(implicit c:String = "") = {println(b); b}

a("1")(a("2")(a("3")))

which prints

3

2

1

How can I get scala to print out this instead?

1

2

3

回答1:

Laziness is always the way to go to invoke code not before it is used. In your example, though, you are not using c at all, which would mean that when it is lazy it would never be invoked at all.

Changing this a little bit would result in:

scala> def a(b: String)(c: => String = "") = {println(b); c; b}
a: (b: String)(c: => String)String

scala> a("1")(a("2")(a("3")()))
1
2
3
res15: String = 1

Here, c is declared as call-by-name, which results in the lazy behavior. However implicit parameters can't be call-by-name, thus we have to use a more heavyweight approach:

scala> import scala.language.implicitConversions
import scala.language.implicitConversions

scala> def a(b: String)(implicit c: () => String = () => "") = {println(b); c(); b}
a: (b: String)(implicit c: () => String)String

scala> implicit def conv(s: => String) = () => s
conv: (s: => String)() => String

scala> a("1")(a("2")(a("3")))
1
2
3
res0: String = 1

Now, the laziness is even more explicit but we need an implicit conversion to allow your original syntax.

In summary you can't just toggle the evaluating order of your function arguments, you have to understand laziness to benefit from it. Nevertheless laziness comes with syntactic overhead (at least in Scala, in Haskell for example it would already be built-in into the language), therefore it leads to a different design of your code.



标签: scala