Insert a print into a partial function

Is there a clever way to insert a println for debugging into a partial function such as the one given to foldLeft below? And if so, how to access the argument?

  def pairList[B](as: List[B]): (List[(B, B)], Option[B]) = {
    val none: Option[B] = None
    val nil: List[(B, B)] = Nil
    as.foldLeft((nil, none)) { // would like to println(...) here
      case ((stack: List[(B, B)], Some(b2: B)), b1: B) => (((b1, b2) :: stack), none)
      case ((stack: List[(B, B)], None), b1: B) => (stack, Some(b1))
    } match {
      case (stack, leftover) => (stack.reverse, leftover)
    }
  }

This is what I usually do, but it seems like there should be an easier way.

  def pairList[B](as: List[B]): (List[(B, B)], Option[B]) = {
    val none: Option[B] = None
    val nil: List[(B, B)] = Nil
    as.foldLeft((nil, none)) { (acc,next) =>
      println(s"acc=$acc  next=$next")
      (acc,next ) match {
      case ((stack: List[(B, B)], Some(b1: B)), b2: B) => (((b1, b2) :: stack), none)
      case ((stack: List[(B, B)], None), b1: B) => (stack, Some(b1))
    } } match {
      case (stack, leftover) => (stack.reverse, leftover)
    }
  }

I think that’s the proper way if you want to do one println per entire pattern matching ladder.

Correction:
I’ve figured out something:

  def foldLeftPrint[A, B](fun: (A, B) => A): (A, B) => A = (acc, next) => {
    println(s"acc=$acc  next=$next")
    fun(acc, next)
  }

  def pairList[B](as: List[B]): (List[(B, B)], Option[B]) = {
    val none: Option[B] = None
    val nil: List[(B, B)] = Nil
    as.foldLeft((nil, none))(foldLeftPrint {
      case ((stack: List[(B, B)], Some(b2: B)), b1: B) =>
        (((b1, b2) :: stack), none)
      case ((stack: List[(B, B)], None), b1: B) =>
        (stack, Some(b1))
    }) match {
      case (stack, leftover) => (stack.reverse, leftover)
    }
  }

Method foldLeftPrint is reusable and everthing seems to typecheck. Nice :slight_smile:

Update:
You can even easily customize the output:

  def foldLeftPrint[A, B](fstName: String, sndName: String)(
    fun: (A, B) => A
  ): (A, B) => A = (fst, snd) => {
    println(s"$fstName=$fst $sndName=$snd")
    fun(fst, snd)
  }

  def pairList[B](as: List[B]): (List[(B, B)], Option[B]) = {
    val none: Option[B] = None
    val nil: List[(B, B)] = Nil
    as.foldLeft((nil, none))(foldLeftPrint("acc", "next") {
      case ((stack, Some(b2)), b1) =>
        (((b1, b2) :: stack), none)
      case ((stack, None), b1) =>
        (stack, Some(b1))
    }) match {
      case (stack, leftover) => (stack.reverse, leftover)
    }
  }

I have this utility function in Querki’s globals:

  def spewing[T](msg:String)(f: => T):T = {
    QLog.spew(s"Trying $msg")
    try {
      val result = f
      QLog.spew(s"  $msg succeeded, returning $result")
      result
    } catch {
      case ex:Exception => { QLog.error(s"  $msg failed", ex); throw ex }
    }
  }

When I need to print something for debugging, I wrap it in this, so I get both the message (which might contain other info) and the return value. Works for more or less all synchronous expressions.

(QLog.spew() is basically a specialized println().)

1 Like