Martin Trueman
Martin Trueman

Reputation: 45

arguments to higher order function weirdness in scala

I'm working on the assignments on Coursera's Scala course and have a question. Out of curiosity, I've switched from an anonymous function to a defined one:

object sets {
  def main(args:Array[String]) {
    type Set = Int => Boolean
    def contains(s: Set, elem: Int): Boolean = {println("in contains elem  ="+elem);s(elem)} 
    def singletonSet(elem: Int): Set = {      //println("in singleton elem ="+elem); (x: Int) => x == elem}

      def singletonSetF(x: Int): Boolean = {
        println ("in singleton elem ="+elem+", x="+x)
        elem == x
      }
      singletonSetF
    }    
    println(contains(singletonSet(69), 6))
  }
}

And here is the output:

in contains elem =6

in singleton elem =69, x=6

false

I believe the code is correct and working properly. My question is how and why does the "elem = 6" argument passed from the contains method, get assigned to "x = 6" in the singletonSetF method? Is the contains function call "s(elem)" a call to singletonSetF rather than singletonSet?

Upvotes: 0

Views: 89

Answers (3)

DNA
DNA

Reputation: 42617

The contains function takes two arguments: a Set and an Int. We are trying to test whether the Set contains the Int.

The Set is actually a function of type Int => Boolean, as defined by the type alias for Set.

We create this first argument by calling singletonSet, which returns a function (singletonSetF). However, singletonSetF is a closure - it captures the value of elem passed into singletonSet, which in this case is 69.

Finally we call s(elem). s is the closure containing the value 69. elem is the value 6, which is then bound to the parameter 'x' in singletonSetF.

Important: The code is a little confusing because you use elem to mean two different things in two different places - in contains, it is the value we are testing for membership of the Set; in singletonSet, it is the sole member of the Set. Renaming one of these may help a lot!

Upvotes: 1

Shadowlands
Shadowlands

Reputation: 15074

Your singletonSetF call, made in the singletonSet method when called with the value 69, results in a Set instance, which in this case is an instance of a function from Int to Boolean (Int => Boolean). The function is created at this point (although it does "close" over the value 69 for elem), not evaluated, so x hasn't been set here.

Then, when contains is called, it runs the line s(elem) where elem here (not the same elem closed over by singletonSetF!) is the paramter value 6.

The line s(elem) is a call to that earlier-created function (s here is the same Set - hence the same Int => Boolean instance - created by the call to singletonSet), passing the value of the parameter elem (passed in to contains as the value 6) into that function.

At this point the function is executed, with x = 6, producing the printed statements you observed.

Upvotes: 1

lex82
lex82

Reputation: 11317

I think the main problem is that you assume that a Set is kind of a fixed data structure once you obtain it from singletonSet. However, it is just a function that can be called. s(elem) calls it and ends up in executing the code in singletonSetF.

Here is what happens: singletonSet(69) calls the singletonSet function. This function returns a function value of the singletonSetF function. The function value acts as kind of a wrapper around a local function or method. You don't see the wrapper but its added implicitly because singletonSetF cannot be returned directly (it's a local function that cannot be passed around).

contains receives this function value which is properly typed as Int => Boolean and calls the function with the value 6. The function value/wrapper then calls the real singletonF with value 6.

Upvotes: 1

Related Questions