-1

I have a macro impl in which I have a function I want to call recursively for nested behavior. I've simplified a trivial count-down example to show the desired effect:

import scala.quoted.*
import quoted.Quotes

//  Desired recursive effect:
//
//  println(Boo.miBoo(3)) produces:
//
//  Number 3 is added.
//  Number 2 is added.
//  Number 1 is added.

object Boo:

  given StringBuilderToExpr: ToExpr[StringBuilder] with {
    def apply(x: StringBuilder)(using Quotes): Expr[StringBuilder] =
      '{ new StringBuilder( { ${Expr(x.toString)} } ) }
  }

  inline def miBoo(n: Int): String = ${ miBooImpl('n) }

  def miBooImpl(n: Expr[Int])(using quotes:Quotes): Expr[String] = {
    import quotes.reflect.* 

    def recursiveFn(): Expr[(Int,StringBuilder)=>StringBuilder] = {
        '{(i:Int, sb:StringBuilder) => 
          val b = sb.append(s"Number $i is added.\n")
          if i > 0 then
            val fn:(Int,StringBuilder)=>StringBuilder = ???  // How can I make this a recursive call to recursiveFn?
            fn(i-1,b)
          b
        }
    }

    val fn = recursiveFn()
    val sb = Expr(new StringBuilder())
    '{ 
      $fn(5, $sb).toString 
    }
  }

recursiveFn() actually builds a function accepting an int and a StringBuilder. I want nested/recursive calls to recursiveFn() inside the '{}.

(I know I can get this output in far easier way--I't the recursive behavior I want to solve. In the real app recursiveFn() does very dynamic/nested things...not just simple output.)

Greg
  • 10,696
  • 22
  • 68
  • 98
  • Can you share the error you get when you just call the method? As you do it already few lines below outside the recursion. – Gaël J Aug 19 '23 at 06:53
  • The only thing I can think of right now is that recursion is limited in macros to few levels IIRC. – Gaël J Aug 19 '23 at 06:54
  • A macro outputs code (AST) and this code has to be of a finite size. It might use loops/recursion to handle input of unbounded size/nesting, but YOU have to take into consideration when dealing with recursive ADTs. When you generate code for them, there should be a mechanism that would handle recursive ADTs by generating code that implements recursion/iteration in runtime. It is often done with implicits and mix of automatic and semiautomatic derivation so that you would assign derived code to the implicit`val`/`def` which would be called somewhere within that code. – Mateusz Kubuszok Aug 19 '23 at 07:56

0 Answers0