Search code examples
scalafold

Scala Type Mismatch in FoldLeft operation


I'm very new to Scala so excuse that this is probably a simple misunderstanding of the language. I have a function:

def compareNextElemToMinElem(lst: List[Int]) = {
    val max = lst.foldLeft((lst(0),lst(0),0)) { (minSoFar:Int, x:Int, maxDiff:Int) => 
        if (x < minSoFar) (minSoFar, x, maxDiff) 
        if (x - minSoFar > maxDiff) (minSoFar, x, x - minSoFar)
        else (minSoFar, x, x - minSoFar)
    }
    max._3
}

Basically it should go one element at a time and track the biggest difference in elements so far. By calling max._3 I hope to return the final maxDiff from the foldLeft call. I'm getting an error:

type mismatch;
 found   : (Int, Int, Int) => (Int, Int, Int)
 required: ((Int, Int, Int), Int) => (Int, Int, Int)
    val max = lst.foldLeft((lst(0),lst(0),0)) { (minSoFar:Int, x:Int, maxDiff:Int) => 

Additionally, I have to put (minSoFar:Int, x:Int, maxDiff:Int) instead of (minSoFar, x, maxDiff) to avoid a missing parameter type error. Why is that?


Solution

  • Both the syntax and logic seemed not entirely correct, here is a possible fix:

    def compareNextElemToMinElem(lst: List[Int]) = {
      lst.foldLeft((lst.head, lst.head)) { case ((minSoFar, maxDiff), x) =>
        if (x < minSoFar) (x, maxDiff) 
        else if (x - minSoFar > maxDiff) (minSoFar, x - minSoFar)
        else (minSoFar, maxDiff)
      }._2
    }
    
    println(compareNextElemToMinElem(List(1,-2,3,-1,4,8,2)))
    

    prints

    10
    

    which is 8 - (-2).

    Brief explanation:

    1. You want to keep track of two values: minSoFar and maxDiff, not three.
    2. You have to look at the content of the list: x must come from the list, not from the "accumulator" that is passed from previous step
    3. fold, in general, takes a function that takes two arguments:

      list.fold(accumulator0){ (acc, currentValue) => nextAcc }
      
    4. Since here your accumulator acc is itself a tuple, you have to pattern match on the first component with case, so:

      list.fold((a0, b0)) { case ((ai, bi), x) => (nextAi, nextBi) }
      
    5. I didn't understand your if-else logic, no guarantee that it does what you intended.